FAB menu
components specs/components/fab-menu.kmd
Material 3 Expressive FAB menu — successor of legacy "speed-dial". ToggleFloatingActionButton + N FloatingActionButtonMenuItems with staggered spring expansion + shape morph (FAB → "X"). Max 6 items (above → migrate to Navigation drawer).
When this spec applies
Primary triggers
- FAB needs to expose multiple secondary actions
All triggers
- Compose-style entry point with 2-6 related actions
- Replace legacy speed-dial in Koder app
Specification body
Spec — FAB menu
Companion:
buttons.kmdFAB section. Animation viamotion.kmdR9.1 spring +shape-library.kmdR2 morph.
Princípios
- 2-6 items — < 2 → use single FAB. > 6 → migrate to Navigation drawer.
- Staggered expansion — items appear in sequence (50-100ms offset) via spring.
- Toggle morph — main FAB morphs FAB → "X" shape on open; reverse on close.
- Anchored above by default — fan upward; auto-flip if window orientation requires.
R1 — Anatomia
Item 3 ⬡ ← label
Item 2 ⬡
Item 1 ⬡
┌──────────────────┐
│ [×] │ ← toggle FAB (morphed)
└──────────────────┘
Slots:
| Slot | Function |
|---|---|
| Toggle FAB | Primary. Tap = open/close menu; shape morph between FAB (default) and "X" (open). |
| Menu items | 1-6 secondary actions; each a small FAB + label chip. |
R2 — Sizes
Toggle FAB sizes inherit buttons.kmd FAB:
- Small (40dp) / Default (56dp) / Large (96dp).
Menu items: small FAB only (40dp) — visually subordinate.
R3 — Anchor + direction
Default: above (fan upward from toggle).
Auto-flip rules:
| Window orientation/class | Direction |
|---|---|
| Compact portrait (mobile) | Above (default) |
| Compact landscape (mobile) | Above (still — UX consistency) |
| Medium/Expanded (tablet/desktop) | Beside (left-of-toggle if RTL; right-of-toggle if LTR) |
| Toggle at top of viewport | Force below (auto-flip) |
| Toggle at side | Force opposite direction |
R4 — Expansion animation
On tap toggle (open):
- Toggle FAB morph: FAB shape → "X" (Cookie-4 → diagonal cross via
shape-library.kmdCookie-4 → Diamond morph). - Items appear: stagger 60ms offset per item; each via
motion-spatial-fastspring (slight overshoot). - Item labels: fade-in via
motion-effect-fast. - Optional scrim: backdrop tint
surface-dim0.4 alpha (configurable).
On tap toggle (close) OR outside tap OR item selection OR ESC:
- Reverse — items fade-out in reverse order (stagger 30ms; faster than open).
- Toggle morph back: "X" → FAB shape.
- Scrim fades out.
R5 — Threshold + alternatives
| Item count | Recommended pattern |
|---|---|
| 1 | Single FAB (no menu) |
| 2-6 | FAB menu (this spec) |
| 7+ | Migrate to Navigation drawer ou Bottom sheet |
Anti-pattern: hiding important destructive actions inside FAB menu (use Confirm dialog instead).
R6 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderFabMenu({toggleIcon, items, onItemTap, direction}) em koder_kit/ (futuro) |
| Web | <koder-fab-menu> em koder_web_kit |
| Compose Android | KoderFabMenu (futuro) |
| SwiftUI iOS | idem (futuro) |
| CLI / TUI | n/a |
R7 — Acessibilidade
- Toggle:
role="button" aria-haspopup="menu" aria-expanded="<state>" aria-label="More actions". - Items:
role="menuitem" aria-label="<action>". - Keyboard: Tab to toggle + Enter opens; Arrow Up/Down navigates items; Enter selects; ESC closes.
- Focus trap: while open, Tab cycles within items + toggle only.
- Screen reader announces toggle state change.
R8 — i18n
| Key | en-US | pt-BR |
|---|---|---|
fab_menu.toggle.label_closed | "More actions" | "Mais ações" |
fab_menu.toggle.label_open | "Close menu" | "Fechar menu" |
R9 — Reduced-motion
Open/close: instant. Toggle morph: skip; show static "X" icon swap. Staggered appearance: replaced by simultaneous fade-in (no stagger).
R10 — Per-preset variation
| Preset | FAB menu style |
|---|---|
material3 / material_expressive | Default morph + stagger spring |
material2 | Simple icon swap + linear stagger (no spring) |
terminal_classic | List below toggle (no animation) |
brutalist | Sharp items; no morph |
cyberpunk_neon | Default + glow on items + connection lines toggle ↔ items |
minimalist_mono | No labels (icon-only); ultra-spartan |
T-suite
- T1 Mount closed: toggle FAB visible; items hidden.
- T2 Open: tap toggle → items appear staggered; toggle morphs to X.
- T3 Item count 3: render 3 items vertically above toggle.
- T4 Direction auto-flip: position toggle at top edge → menu opens BELOW.
- T5 Tablet landscape: render direction = beside.
- T6 Item select: tap item → menu closes; onItemTap fires.
- T7 Outside tap closes: tap scrim → menu closes.
- T8 ESC closes: menu open + ESC → closes.
- T9 Keyboard nav: arrows + Enter functional.
- T10 Reduced-motion: instant open/close.
- T11 A11y: focus trap; aria-expanded transitions.
- N1 > 6 items: spec validation OR runtime warning suggesting Navigation drawer.
Cross-link
- Companion:
buttons.kmdFAB variants - Animation drivers:
motion.kmdR9.1,shape-library.kmdR2 - Layout:
app-layout/window-size-classes.kmd(direction rules) - Migration when > 6 items:
navigation.kmddrawer - Refs: M3 FAB menu pattern; legacy speed-dial replaced
References
specs/components/buttons.kmdspecs/themes/motion.kmdspecs/themes/shape-library.kmdspecs/app-layout/window-size-classes.kmd