Floating Action Button (FAB)
Floating action buttons help people take the primary action in an app. They are shaped like a floating circled icon and move forward over other content.
Floating action buttons (FABs) represent the most important action on a screen. Expressive FABs use shape morphing on tap, elevation, and Ripple effects to communicate interaction.
Introduction
The MD3 Expressive FAB is the pinnacle of the interface hierarchy. It is designed to be easily reachable and visually distinct. Unlike standard buttons, the FAB "floats" above all other content, using elevation and shadow to define its spatial position. In the Expressive spec, the FAB features a unique shape-morphing animation on press, providing tactile confirmation of the action.
Anatomy
- Container: A rounded-square surface that holds the icon.
- Icon: A clear visual representation of the primary action (e.g., Add, Edit, Compose).
- State Layer: Shows hover and pressed states with a ripple effect and shape-morphing.
- Shadow / Elevation: Defines the card's depth relative to the underlying content.
Variants
Sizes
MD3 Expressive defines four FAB sizes:
- Small (
sm- 40dp): Recommended for tight layouts or embedded content actions. - Medium (
md- 56dp): Standard primary action button. - Large (
lg- 96dp): High emphasis action. - Extra-Large (
xl- 136dp): Spotlight action element.
Color Styles
FABs support various color roles from the MD3 scheme, allowing you to match the emphasis of the action to your branding.
Features
Shape Morphing
On press, the FAB container morphs its border-radius inward, creating a "squish" effect that communicates interactivity through motion.
Lowered State
Use the lowered prop when the FAB is placed in a container that already provides visual separation from the background, such as a Navigation Rail.
Position Wrapper
The FABPosition component helps you easily pin the FAB to a screen corner (default bottom-right).
Usage
Basic Usage
import { FAB, Icon } from "@bug-on/m3-expressive";
<FAB
icon={<Icon name="add" />}
aria-label="Create new item"
onClick={() => handleCreate()}
/>
With Fixed Positioning
import { FAB, FABPosition, Icon } from "@bug-on/m3-expressive";
<FABPosition position="bottom-right">
<FAB icon={<Icon name="edit" />} aria-label="Edit" />
</FABPosition>
Next.js Integration (asChild)
Use asChild to wrap Next.js Link with FAB styling and entrance/exit animations.
import Link from "next/link";
import { FAB, Icon } from "@bug-on/m3-expressive";
<FAB asChild aria-label="Compose Mail">
<Link href="/compose">
<Icon name="edit" />
</Link>
</FAB>
Best Practices
Do
- Use only one FAB per screen.
- Place the FAB in a consistent location (usually the bottom-right corner).
- Use a clear, meaningful icon.
- Ensure the FAB is used for the most important "positive" action on the screen.
Don't
- Don't use a FAB for minor or destructive actions (e.g., "Delete").
- Don't use more than one FAB on a single screen.
- Don't hide the FAB unless it's necessary for the user flow (e.g., during a specific scrolling event).
Accessibility
- Required Label: The
aria-labelprop is mandatory for icon-only FABs. - Touch Target: The small FAB includes an automatic touch target expander for accessibility.
- Keyboard: Fully reachable via
Tab.SpaceorEntertriggers the action. - Motion: All animations (scaling, morphing) respect
prefers-reduced-motion.
API Reference
FAB
| Prop | Type | Default | Description |
|---|---|---|---|
icon | ReactNode | — | Required. Icon element to display. |
size | "sm" | "md" | "lg" | "xl" | "md" | MD3 size variant (sm=40dp, md=56dp, lg=96dp, xl=136dp). |
colorStyle | "primary" | "secondary" | "tertiary" | "surface" | "primary" | MD3 color role style. |
extended | boolean | false | Expands FAB to reveal label passed as children. |
lowered | boolean | false | Reduces container shadow to lowered elevation. |
loading | boolean | false | Displays loading spinner and disables click interactions. |
loadingVariant | "loading-indicator" | "circular" | "loading-indicator" | Loading indicator variant style. |
visible | boolean | true | Controls FAB entrance/exit scale motion animation. |
asChild | boolean | false | Merges props onto child element (e.g., Next.js Link). |
aria-label | string | — | Accessible label (required for icon-only FABs). |
FABPosition
| Prop | Type | Default | Description |
|---|---|---|---|
position | "bottom-right" | "bottom-left" | "top-right" | "top-left" | "bottom-right" | Screen corner position to anchor FAB. |
children | ReactNode | — | Required. Child element (typically a <FAB>). |
className | string | — | Additional CSS class for container customization. |