Floating Action Button (FAB) Menu
The FAB menu opens from a Floating Action Button to display multiple related actions with smooth MD3 staggered animations.
Floating Action Button menus help group related actions under a single, prominent floating button. On tap, the FAB transforms and reveals a list of specific actions.
Introduction
The MD3 Expressive FAB Menu (or Speed Dial) is an advanced variant of the FAB. It allows a single primary action button to expand into a suite of related actions, saving screen space while keeping multiple options easily accessible. It features high-end staggered entrance animations and a fluid transformation of the main toggle button.
Anatomy
- Main FAB (Toggle): The primary button that the user interacts with to open the menu. Often changes its icon (e.g., from "Add" to "Close") when expanded.
- Menu Items: A vertical list of secondary action buttons that appear above the main FAB.
- Labels: Descriptive text for each menu item, typically displayed next to the secondary icons.
- Click-Outside Dismiss: Dismisses the open menu on outside pointer interactions without rendering a full-screen blocking overlay, preserving page scroll and background element interactions.
Variants
Sizes
The main toggle FAB supports the three standard MD3 Expressive sizes:
- Baseline (Default /
sm): 56dp - Medium (
md): 80dp - Large (
lg): 96dp
Color Styles
FAB Menus can be styled using Primary, Secondary, or Tertiary container roles, which are applied consistently to the toggle and all menu items.
Features
Staggered Animations
When the menu opens, the items appear one after another with a slight delay, creating a fluid, "waterfall" effect that is a hallmark of Material Design 3 Expressive.
Alignment
Items can be aligned to the start, end, or center relative to the toggle FAB, allowing for flexible positioning in different corners or edges of the screen.
Click Outside to Close
Clicking or tapping anywhere outside the open menu container automatically dismisses it. Because this is powered by document-level event listeners rather than a blocking modal overlay, background elements (such as buttons, links, and scroll areas) remain interactive.
This behavior is enabled by default and can be disabled by setting closeOnBackdropClick={false}.
Usage
Basic Usage
import { FABMenu, Icon } from "@bug-on/m3-expressive/buttons";
import * as React from "react";
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const actions = [
{ id: "image", label: "Image", icon: <Icon name="image" />, onClick: () => {} },
{ id: "video", label: "Video", icon: <Icon name="videocam" />, onClick: () => {} },
{ id: "file", label: "File", icon: <Icon name="description" />, onClick: () => {} },
];
return (
<FABMenu
expanded={isOpen}
onToggle={setIsOpen}
items={actions}
aria-label="Create new content"
/>
);
}
Disabling Click-Outside Dismiss
If you want the menu to only close via explicit interaction with the toggle button, an action item, or the Escape key, set closeOnBackdropClick={false}:
<FABMenu
expanded={isOpen}
onToggle={setIsOpen}
items={actions}
closeOnBackdropClick={false}
aria-label="Sticky actions menu"
/>
Best Practices
Do
- Use a FAB Menu for 3 to 6 related actions.
- Ensure the main toggle icon clearly communicates that it can be expanded (e.g., an "Add" or "Menu" icon).
- Provide clear labels for all secondary actions.
- Use consistent color styles for all elements in the menu.
Don't
- Don't use a FAB Menu for actions that are completely unrelated.
- Avoid putting more than 6 actions in a single FAB Menu; it can become difficult to use and visually cluttered.
- Don't use a FAB Menu if the actions are critical and should be always visible (use a Toolbar instead).
Accessibility
- Keyboard: Press
Escto close the menu. UseArrowUp/ArrowDownorTab/Shift+Tabto navigate through items. - Outside pointer: Clicking or tapping outside automatically closes the menu.
- Roles: Correctly implements
role="group"on outer container,role="menu"on list, androle="menuitem"on actions. - States: Uses
aria-expandedandaria-haspopup="menu"on the main toggle button. - Labels: Every menu item supports a
labelfor visual clarity and accessibility.
API Reference
FABMenu
| Prop | Type | Default | Description |
|---|---|---|---|
expanded | boolean | — | Required. Controlled open state. |
onToggle | (open: boolean) => void | — | Required. Open state change callback. |
items | FABMenuItemData[] | — | Required. Array of action items. |
colorVariant | "primary" | "secondary" | "tertiary" | "primary" | MD3 container color role. |
size | "sm" | "md" | "lg" | "sm" | FAB size variant controlling container dimensions per MD3 spec. |
alignment | "start" | "end" | "center" | "end" | Menu items alignment relative to Toggle FAB. |
closeOnBackdropClick | boolean | true | When true, clicking/tapping outside the menu container closes it. |
focusLast | boolean | true | Moves focus to the last item (closest to FAB) when expanded. |
className | string | — | Custom CSS className for container. |
aria-label | string | — | Accessible label for Toggle FAB and container group. |
FABMenuItemData
| Property | Type | Default | Description |
|---|---|---|---|
id | string | — | Required. Unique ID used for React keys and focus tracking. |
label | string | — | Descriptive label adjacent to icon. Omit for icon-only item. |
icon | ReactNode | — | Required. Icon element. |
onClick | () => void | — | Required. Action callback when activated. |
disabled | boolean | false | Disables interaction while preserving focusability (aria-disabled). |
className | string | — | Additional CSS class names for item. |