Toolbars (docked + floating)
components specs/components/toolbars.kmd
Material 3 Expressive Toolbars — substituem o legado Bottom App Bar. Two variants: docked (anchored bottom, 56dp) and floating (horizontal bottom-center OR vertical side, hide-on-scroll). Companion to FAB. Bottom app bar marked deprecated-in-expressive.
Quando esta spec se aplica
Triggers primários
- Build contextual action row distinct from app navigation
Todos os triggers
- Replace bottom app bar in Koder app
- Add contextual actions row anchored to viewport
- Pair toolbar with FAB
Corpo da especificação
Spec — Toolbars (docked + floating)
Sibling:
app-bars.kmd(navegação principal). Esta spec cobre contextual actions (toolbars), distintos de navegação.
Princípios
- App-bar ≠ Toolbar — app-bar é navegação principal (
app-bars.kmd). Toolbar é ações contextuais. - Two anchored variants — docked (anchor fixo bottom) vs floating (translucent, hide-on-scroll).
- Pair com FAB — floating toolbar mais comum pareando com FAB no canto.
- Bottom app bar deprecated-in-expressive — manter retro-compat, mas não recomendar pra novos surfaces.
R1 — Decision tree
Need contextual actions row?
├── NO → use app bar (navegação)
└── YES:
├── Few actions, persistent → docked toolbar (R2)
├── Many actions OR auto-hide preferred → floating toolbar (R3)
│ ├── Horizontal default (bottom-center)
│ └── Vertical (tablet/desktop, side-anchored)
└── Legacy/migration → bottom app bar (deprecated)
R2 — Docked toolbar
- Anchor: bottom of viewport (above safe-area inset per
app-layout/safe-area.kmd). - Height: 56dp.
- Max actions: 5 (above → migrate to floating OR menu).
- Background:
surfacepercolor-roles.kmd. - Elevation: 1dp (subtle).
- Scroll behavior: lift-on-scroll (slight elevation increase) OR hide-on-scroll-down (configurable).
R2.1 — Anatomia
┌──────────────────────────────────────────┐
│ [Action] [Action] [Action] [Action] [⋯] │ ← 56dp height
└──────────────────────────────────────────┘
Actions: icon-only OR icon+label (configurable per action). Overflow ⋯ quando > 5.
R3 — Floating toolbar
R3.1 — Horizontal floating
- Anchor: bottom-center, floating above content (with backdrop blur OR translucent).
- Width: hug-content (min 240dp / max 80% viewport).
- Padding: 16dp from bottom edge (above safe-area).
- Elevation: 3dp.
- Shape:
shape-corner-extra-large(pill). - Background:
surface-container-highpercolor-roles.kmd. - Behavior: hide-on-scroll-down + reveal-on-scroll-up via spring (
motion.kmdR9.1motion-spatial-default).
R3.2 — Vertical floating
- Anchor: right-edge (LTR) or left-edge (RTL); vertically centered or top.
- Tablets/desktops (Medium+ window class).
- Auto-pin/unpin via drag.
- Same elevation + shape + background as horizontal.
R3.3 — FAB pairing
Floating toolbar comumente paired com FAB:
┌─┐
│+│ ← FAB
└─┘
┌──────────────────────┐
│ [A] [B] [C] │ ← Floating toolbar (bottom-left)
└──────────────────────┘
FAB scrolls/hides independently OR paired (configurable per surface).
R4 — Bottom app bar deprecation
app-bars.kmd bottom variant marked deprecated-in-expressive:
- Retain support pra apps que ainda usam (no breaking change).
- New surfaces SHOULD use docked toolbar instead.
- Migration warning visible em
koder-spec-auditquando bottom app bar detected em new code.
R5 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderDockedToolbar({actions}) + KoderFloatingToolbar({actions, direction}) em koder_kit/ (futuro) |
| Web | <koder-docked-toolbar> + <koder-floating-toolbar direction="horizontal|vertical"> |
| Compose Android | KoderDockedToolbar + KoderFloatingToolbar (futuro) |
| SwiftUI iOS | idem (futuro) |
| CLI / TUI | Status line actions; no floating |
R6 — Acessibilidade
- Toolbar:
role="toolbar" aria-label="<context>". - Actions: standard button semantic per
buttons.kmd. - Floating: focus-trap NOT applied (open / not modal).
- Hide-on-scroll: aria-hidden="true" when hidden; revealed restores.
- Keyboard: Tab through actions; arrow keys navigate (per Material toolbar pattern).
R7 — i18n
| Key | en-US | pt-BR |
|---|---|---|
toolbar.label.actions | "Actions" | "Ações" |
toolbar.overflow | "More" | "Mais" |
R8 — Reduced-motion
Hide-on-scroll: instant (no spring slide). Lift-on-scroll: elevation change instant.
R9 — Per-preset variation
| Preset | Toolbar style |
|---|---|
material3 / material_expressive | Default (docked + floating com shape pill) |
material2 | Docked only (sharp corners); floating not supported |
terminal_classic | Bottom row text-only; no floating |
brutalist | Sharp corners; flat (no elevation/shadow) |
cyberpunk_neon | Default + neon outline on floating |
minimalist_mono | Single border-top; no fill |
glassmorphism | Floating backdrop-blur 30% (heavier) |
T-suite
- T1 Docked mount: 3 actions render at bottom; height 56dp.
- T2 Docked overflow: 6 actions → 5 visible +
⋯overflow menu. - T3 Floating horizontal mount: bottom-center; pill shape; elevation 3dp.
- T4 Floating hide-on-scroll: scroll down 100px → toolbar slides out; scroll up → slides back.
- T5 Floating vertical: Medium window class → side-anchored.
- T6 FAB pair: floating toolbar + FAB → both anchor independently OR paired per config.
- T7 Bottom app bar deprecation: existing instances continue to work; audit warns on new uses.
- T8 Reduced-motion: hide/reveal instant.
- T9 A11y: role="toolbar"; keyboard nav functional.
Cross-link
- Sibling:
app-bars.kmd(navegação) - Companion:
buttons.kmd, FAB section - Layout:
app-layout/safe-area.kmdR-safe-area - Animation:
motion.kmdR9 - Refs: M3 Toolbars guidelines
Requirements (testable)
Requirement: Docked toolbar anchoring and capacity {#req-toolbars-docked}
The docked toolbar SHALL anchor to the bottom of the viewport above the safe-area inset with a fixed height of 56dp, render at most 5 actions inline, and collapse any actions beyond the fifth into an overflow (⋯) menu.
Scenario: Mount with three actions
- GIVEN a docked toolbar configured with 3 actions
- WHEN the toolbar mounts
- THEN all 3 actions render in a single row anchored at the bottom of the viewport
- AND the toolbar height measures 56dp
- AND the toolbar sits above the safe-area inset
Scenario: Overflow beyond five actions
- GIVEN a docked toolbar configured with 6 actions
- WHEN the toolbar mounts
- THEN exactly 5 actions render inline
- AND a trailing
⋯overflow control is shown - AND activating
⋯reveals the 6th action in an overflow menu
Requirement: Horizontal floating toolbar presentation and hide-on-scroll {#req-toolbars-floating-horizontal}
The horizontal floating toolbar SHALL float bottom-center above content with shape-corner-extra-large (pill) shape and 3dp elevation, and SHALL hide on scroll-down and reveal on scroll-up.
Scenario: Mount bottom-center as pill
- GIVEN a horizontal floating toolbar
- WHEN the toolbar mounts
- THEN it is anchored bottom-center, floating above the content
- AND its shape is
shape-corner-extra-large(pill) - AND its elevation is 3dp
Scenario: Hide on scroll down and reveal on scroll up
- GIVEN a visible horizontal floating toolbar
- WHEN the content is scrolled down by 100px
- THEN the toolbar slides out of view
- WHEN the content is subsequently scrolled up
- THEN the toolbar slides back into view
Requirement: Vertical floating toolbar on Medium+ window class {#req-toolbars-floating-vertical}
The vertical floating toolbar SHALL side-anchor (right edge in LTR, left edge in RTL) only on Medium or larger window classes, retaining the same elevation, shape, and background as the horizontal variant.
Scenario: Side-anchored on a Medium window
- GIVEN a floating toolbar with vertical direction on a Medium window class
- WHEN the toolbar mounts in an LTR layout
- THEN the toolbar is anchored to the right edge
- AND it uses the same 3dp elevation, pill shape, and
surface-container-highbackground as the horizontal variant
Requirement: Bottom app bar deprecation without breakage {#req-toolbars-deprecation}
Existing bottom app bar instances SHALL continue to function with no breaking change, and koder-spec-audit SHALL emit a migration warning when a bottom app bar is detected in new code while docked toolbar remains the recommended replacement.
Scenario: Existing instance keeps working
- GIVEN a surface already using a bottom app bar
- WHEN the surface is rendered after the deprecation
- THEN the bottom app bar renders and functions unchanged
Scenario: Audit warns on new usage
- GIVEN new code that introduces a bottom app bar
- WHEN
koder-spec-auditruns against that code - THEN a migration warning is reported recommending the docked toolbar
Requirement: Toolbar accessibility semantics and keyboard navigation {#req-toolbars-a11y}
A toolbar SHALL expose role="toolbar" with an aria-label for its context, SHALL support Tab-into and arrow-key navigation across its actions, SHALL NOT apply a focus trap to floating toolbars, and SHALL set aria-hidden="true" while hidden by scroll and restore it on reveal.
Scenario: Role, label, and keyboard traversal
- GIVEN a mounted toolbar with multiple actions
- WHEN the toolbar is inspected
- THEN it exposes
role="toolbar"with a non-emptyaria-label - AND Tab moves focus into the toolbar
- AND arrow keys move focus between actions
Scenario: Floating toolbar is not modal
- GIVEN a visible floating toolbar
- WHEN focus moves via Tab while the toolbar is open
- THEN focus is able to leave the toolbar
- AND no focus trap is applied
Scenario: Hidden state marks aria-hidden
- GIVEN a floating toolbar hidden by scroll-down
- WHEN its accessibility state is inspected
- THEN it exposes
aria-hidden="true" - WHEN it is revealed on scroll-up
- THEN
aria-hiddenis removed
Requirement: Reduced-motion instant transitions {#req-toolbars-reduced-motion}
Under a reduced-motion preference, the toolbar SHALL perform hide-on-scroll and reveal without a spring slide and SHALL apply lift-on-scroll elevation changes instantly.
Scenario: Instant hide under reduced motion
- GIVEN reduced-motion is enabled
- AND a visible floating toolbar
- WHEN the content is scrolled down past the hide threshold
- THEN the toolbar disappears instantly with no slide animation
Referências
specs/components/app-bars.kmdspecs/components/buttons.kmdspecs/app-layout/safe-area.kmdspecs/themes/motion.kmd