App bars
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.
Spec — App bars
Facet *isual*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 |
|---|---|---|
| *op* | Page title + nav + primary actions | All surfaces |
| *ottom* | 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 |
|---|---|---|---|
| *enter-aligned* | 64 px | Centered, single line | Mobile, primary screen, simple title |
| *mall* | 64 px | Left-aligned, single line | Default for most screens |
| *edium* | 112 px | Large title below toolbar row, scrolls into row on overflow | Hero screen with strong identity |
| *arge* | 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 scrolly > titleheight. This is the canonical collapse pattern.
Anatomy (small top bar)
┌────────────────────────────────────────────────┐
│ ☰ Page title ◷ ⋮ 👤 │
└────────────────────────────────────────────────┘
↑ ↑ ↑ ↑ ↑
nav title action overflow user- *eight* 64 px
- *orizontal padding* 16 px
- *av icon slot* 24 px icon, left edge, optional
- *itle*
title-large(22/28, weight 500) - *ction slots* up to 3 icon buttons + 1 overflow menu
- *ontainer bg*
surface-container(light: tinted; dark: tonal)
R2 — Action slot rules
- *aximum 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 |
|---|---|
| *tatic* | Title is text only |
| *ith subtitle* | Title + 14 px subtitle below (small bar height 72 px) |
| *ith breadcrumb* | Stack: breadcrumb above small title; OR replace title with full breadcrumb path |
| *ditable* | 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 |
|---|---|---|
| *mall / Center* | Surface tint deepens (elevation overlay) when content is below | Tint clears at top |
| *edium / Large* | Title row collapses; toolbar stays | Title row expands back when at top |
| *inned* | Always visible (default) | — |
| *ift |
Hidden on scroll |
Re |
| *lways-show* | Never hides | — |
Pick ONE scroll behavior per screen; don't mix.
R5 — Bottom app bar (mobile primary)
Anatomy:
┌────────────────────────────────────────────────┐
│ ⌂ ⌥ ⌽ ⊕ │
└────────────────────────────────────────────────┘
↑ ↑ ↑ ↑
actions (left-aligned) FAB (right)- *eight* 80 px (includes 24 px FAB cradle space)
- *ction slots* up to 4 icon buttons, left-aligned
- *AB 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 |
|---|---|
| *ight* | Default; thumb-reach for primary action |
| *enter* | Single dominant action; bar holds 2 actions max each side |
| *o 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 |
|---|---|
| *est* | Default colors |
| *crolled content underneath* | Surface tint deepens (Material 3 elevation overlay), 3 dp tonal lift |
| *overed (icon button)* | State layer 8% on icon hit area |
| *ressed* | State layer 12% |
| *ocused* | 2 px focus ring around icon button |
| *isabled (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
tocontent 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 gesturenav - ❌ 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