App bars
components specs/components/app-bars.kmd
Horizontal bar anchored at the top or bottom of an application surface — holds page title, primary navigation actions, and contextual actions. Material parity (`/components/top-app-bar` and `/components/bottom-app-bar`). Covers center/small/medium/large top bar variants and the bottom bar with FAB integration.
Quando esta spec se aplica
Triggers primários
- Implement a top app bar
- Implement a bottom app bar
Todos os triggers
- Add a top toolbar with title + actions
- Embed contextual actions for the current screen
- Replace title bar with a scrollable header
- Add a thumb-reach action bar at the bottom of a mobile screen
Corpo da especificação
Spec — App bars
Facet Visual of Koder Design. Material parity: https://m3.material.io/components/top-app-bar and https://m3.material.io/components/bottom-app-bar.
2 anchor positions
| Position | Use | Surfaces |
|---|---|---|
| Top | Page title + nav + primary actions | All surfaces |
| Bottom | Thumb-reach actions on mobile / tablet portrait | Mobile + tablet portrait |
Always at most ONE top bar and ONE bottom bar per screen. Do not stack two top bars; nest a secondary toolbar inside content if needed.
R1 — Top bar variants
| Variant | Height | Title | When |
|---|---|---|---|
| Center-aligned | 64 px | Centered, single line | Mobile, primary screen, simple title |
| Small | 64 px | Left-aligned, single line | Default for most screens |
| Medium | 112 px | Large title below toolbar row, scrolls into row on overflow | Hero screen with strong identity |
| Large | 152 px | Display-style title with breathing room | Branded / landing-level screen |
Medium and Large COLLAPSE into Small on scroll: title slides up into the toolbar row at scroll-y > title-height. This is the canonical collapse pattern.
Anatomy (small top bar)
┌────────────────────────────────────────────────┐
│ ☰ Page title ◷ ⋮ 👤 │
└────────────────────────────────────────────────┘
↑ ↑ ↑ ↑ ↑
nav title action overflow user
- Height: 64 px
- Horizontal padding: 16 px
- Nav icon slot: 24 px icon, left edge, optional
- Title:
title-large(22/28, weight 500) - Action slots: up to 3 icon buttons + 1 overflow menu
- Container bg:
surface-container(light: tinted; dark: tonal)
R2 — Action slot rules
- Maximum 3 visible icon actions; rest into overflow (
⋮) - Order from left to right by frequency / importance
- Each action is a 24 px icon button with 48 × 48 px hit target
- Action labels live in tooltip (long-press on mobile, hover on desktop)
- Disable actions don't collapse — show at 38% opacity
R3 — Title behavior
| Mode | Behavior |
|---|---|
| Static | Title is text only |
| With subtitle | Title + 14 px subtitle below (small bar height 72 px) |
| With breadcrumb | Stack: breadcrumb above small title; OR replace title with full breadcrumb path |
| Editable | Tap title opens inline rename input (rare; for renameable doc/board screens) |
Never wrap title to a 2nd line in small/center. Truncate with ellipsis or use Medium/Large variant.
R4 — Scroll behavior
| Variant | On scroll-down | On scroll-up |
|---|---|---|
| Small / Center | Surface tint deepens (elevation overlay) when content is below | Tint clears at top |
| Medium / Large | Title row collapses; toolbar stays | Title row expands back when at top |
| Pinned | Always visible (default) | — |
| Lift-on-scroll | Hidden on scroll-down past threshold; revealed on scroll-up | Re-appears on scroll-up |
| Always-show | Never hides | — |
Pick ONE scroll behavior per screen; don't mix.
R5 — Bottom app bar (mobile primary)
Anatomy:
┌────────────────────────────────────────────────┐
│ ⌂ ⌥ ⌽ ⊕ │
└────────────────────────────────────────────────┘
↑ ↑ ↑ ↑
actions (left-aligned) FAB (right)
- Height: 80 px (includes 24 px FAB cradle space)
- Action slots: up to 4 icon buttons, left-aligned
- FAB cradle: right side, FAB sits on bar (notched on Material 2, flat on Material 3)
- Container bg:
surface-container - Elevation: 2 dp (sits above scrolling content)
Use bottom bar ONLY on mobile + tablet portrait. On larger surfaces, move actions to top bar or side rail.
R6 — Bottom bar + FAB
| FAB position | Use |
|---|---|
| Right | Default; thumb-reach for primary action |
| Center | Single dominant action; bar holds 2 actions max each side |
| No FAB | Bottom bar with up to 4 actions, no embedded FAB |
FAB anchored to bottom bar cradle stays visible when bar scrolls.
R7 — Surface adaptation
App bars MUST adapt per app-layout/window-size-classes.kmd:
| Class | Top bar | Bottom bar |
|---|---|---|
| Compact (< 600 dp) | Small + Center-aligned | Allowed |
| Medium (600-839 dp) | Small (medium for hero) | Allowed (tablet portrait) |
| Expanded (840-1199 dp) | Small / Medium | Forbidden (use side rail) |
| Large (≥ 1200 dp) | Small / Medium | Forbidden (use drawer) |
R8 — States
| State | Visual |
|---|---|
| Rest | Default colors |
| Scrolled content underneath | Surface tint deepens (Material 3 elevation overlay), 3 dp tonal lift |
| Hovered (icon button) | State layer 8% on icon hit area |
| Pressed | State layer 12% |
| Focused | 2 px focus ring around icon button |
| Disabled (action) | 38% opacity |
R9 — Accessibility
- Top bar:
role="banner"on container - Title: heading level matches page hierarchy (h1 on landing page)
- Nav icon:
aria-label="Open navigation"or specific verb - Actions: each icon has
aria-label; overflow hasaria-label="More actions" - Bottom bar:
role="navigation"if actions navigate; else no role - Keyboard order: nav → title (focusable if editable) → actions → overflow → FAB
- Skip-to-content link before app bar for screen readers
R10 — Per-preset variation
| Preset | Top bar | Bottom bar |
|---|---|---|
material3 | Tonal surface, no border | Notch flat, 24 dp corner |
material2 | Flat color, 4 dp shadow | FAB notch on bar |
ios_cupertino | Translucent blur, 1 px hairline border | Tab bar pattern (not bottom app bar — re-map to nav bar) |
gnome | Headerbar style, integrated with window controls | Not used (desktop) |
windows_11 | Mica backdrop, integrated title bar | Not used (desktop) |
brutalist | Solid color, no elevation, thick 4 px bottom border | Sharp corners, no FAB cradle |
terminal_classic | Single text line ═ Page Title ═ | Bottom row [F1] [F2] [F3] style |
R11 — Forbidden patterns
- ❌ Two top bars stacked on one screen
- ❌ Bottom bar on Expanded/Large window-size class
- ❌ More than 3 icon actions visible in top bar (use overflow)
- ❌ More than 4 actions in bottom bar
- ❌ Title that wraps to 2 lines in Small / Center variant
- ❌ Bottom bar without safe-area inset on iOS / Android gesture-nav
- ❌ Hiding action labels entirely (always provide tooltip +
aria-label) - ❌ Animating the title across the entire bar width on collapse (jarring)
Cross-link
app-layout/safe-area.kmd— bottom bar must respect gesture-nav insetapp-layout/window-size-classes.kmd— adaptive per breakpointthemes/elevation.kmd— scroll-state tonal overlaythemes/color-roles.kmd—surface-containertokeninteraction/states.kmd— icon button statesfoundations/elements.kmd— Container family (bar) + Control family (actions)components/navigation.kmd— sibling for primary navigation containers
Requirements (testable)
Requirement: Single top and single bottom bar per screen {#req-app-bars-single-instance}
A screen SHALL render at most one top app bar and at most one bottom app bar; two top bars SHALL NOT be stacked on the same screen, and any secondary toolbar SHALL be nested inside content instead.
Scenario: Second top bar is rejected
- GIVEN a screen that already has one top app bar
- WHEN a second top app bar is added to the same screen
- THEN the layout is rejected as invalid
- AND only one element with
role="banner"exists in the screen
Scenario: One top and one bottom bar coexist
- GIVEN a mobile screen
- WHEN a top app bar and a bottom app bar are both mounted
- THEN exactly one top bar and exactly one bottom bar are present
- AND neither bar is duplicated
Requirement: Top bar variant heights and collapse {#req-app-bars-top-variants}
Top bar variants SHALL use their canonical heights (Center-aligned 64 px, Small 64 px, Medium 112 px, Large 152 px), and Medium and Large variants SHALL collapse their title into the toolbar row once scroll-y exceeds the title height.
Scenario: Medium variant collapses on scroll
- GIVEN a Medium top app bar with height 112 px and content below it
- WHEN the content is scrolled so scroll-y exceeds the title height
- THEN the title row collapses and the title slides up into the toolbar row
- AND the toolbar row remains visible
Scenario: Large variant expands back at top
- GIVEN a Large top app bar collapsed after scrolling down
- WHEN the content is scrolled back to scroll-y 0
- THEN the title row expands back to the 152 px display-style layout
Scenario: Small variant renders at canonical height
- GIVEN a Small top app bar
- WHEN it is rendered
- THEN its container height is 64 px with 16 px horizontal padding
Requirement: Visible action slot limits with overflow {#req-app-bars-action-slots}
A top app bar SHALL show at most 3 visible icon actions with additional actions moved into an overflow menu, and a bottom app bar SHALL show at most 4 icon actions.
Scenario: Fourth top-bar action moves to overflow
- GIVEN a top app bar configured with 5 icon actions
- WHEN the bar is rendered
- THEN exactly 3 icon buttons are visible in the action area
- AND the remaining actions appear inside the overflow (
⋮) menu
Scenario: Fifth bottom-bar action is rejected
- GIVEN a bottom app bar
- WHEN a 5th icon action is added
- THEN the configuration is rejected with at most 4 actions allowed
Requirement: Single scroll behavior per screen {#req-app-bars-scroll-behavior}
A screen SHALL apply exactly one top-bar scroll behavior (Pinned, Lift-on-scroll, or Always-show), and scroll behaviors SHALL NOT be mixed on the same bar.
Scenario: Lift-on-scroll hides then reveals
- GIVEN a top app bar with Lift-on-scroll behavior
- WHEN content is scrolled down past the hide threshold
- THEN the bar hides
- WHEN content is then scrolled back up
- THEN the bar re-appears
Scenario: Mixing scroll behaviors is rejected
- GIVEN a top app bar assigned the Pinned behavior
- WHEN a second scroll behavior is also assigned to the same bar
- THEN the configuration is rejected as invalid
Requirement: Bottom bar forbidden on expanded and large surfaces {#req-app-bars-surface-adaptation}
The bottom app bar SHALL be used only on Compact and Medium (tablet portrait) window-size classes, and SHALL NOT be rendered on Expanded (840–1199 dp) or Large (≥ 1200 dp) surfaces where actions move to a side rail or drawer.
Scenario: Bottom bar allowed on compact
- GIVEN a Compact window-size class (< 600 dp)
- WHEN a bottom app bar is requested
- THEN the bottom app bar renders
Scenario: Bottom bar suppressed on expanded
- GIVEN an Expanded window-size class (840–1199 dp)
- WHEN a bottom app bar is requested
- THEN the bottom app bar is not rendered
- AND the actions are placed in the side rail instead
Requirement: App bar accessibility semantics {#req-app-bars-accessibility}
App bars SHALL expose correct roles and labels: the top bar container SHALL carry role="banner", every icon action SHALL have an aria-label, the overflow control SHALL be labelled "More actions", and keyboard focus order SHALL proceed nav → title → actions → overflow → FAB.
Scenario: Top bar exposes banner role and labelled actions
- GIVEN a top app bar with a nav icon, title, two icon actions, and an overflow menu
- WHEN the accessibility tree is inspected
- THEN the container has
role="banner" - AND each icon action has a non-empty
aria-label - AND the overflow control has
aria-label="More actions"
Scenario: Keyboard order follows nav to FAB
- GIVEN a screen with a top app bar, actions, overflow, and an anchored FAB
- WHEN the user tabs through focusable elements
- THEN focus visits nav, then title (if focusable), then actions, then overflow, then FAB in that order
Referências
specs/foundations/elements.kmdspecs/themes/elevation.kmdspecs/themes/color-roles.kmdspecs/interaction/states.kmdspecs/app-layout/safe-area.kmd