Floating Action Button
Preview: Single
Floating action button. With `actions` it becomes a speed dial: the main button toggles a stack of labelled mini-buttons (aria-expanded). `fixed` pins it to the viewport, otherwise to the nearest positioned parent.
Import
import { FloatButton } from '@marbleui/ui'Props
<FloatButton>
| Prop | Type | Default | Description |
|---|---|---|---|
| icon *required | ReactNode | — | |
| label *required | string | — | |
| actions | FloatAction[] | — | |
| className | string | — | |
| fixed | boolean | — | |
| onPress | () => void | — | |
| position | 'bottom-right' | 'bottom-left' | 'top-right' | 'bottom-right' |
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitive: React Aria Button. Follow the primitive's docs for the full keyboard map.
Usage notes
Round button pinned to a corner for a screen’s main action; with actions it becomes a speed dial. For actions on a selection use ActionBar.
<FloatButton fixed label="New message" icon={<PlusIcon />} onPress={compose} />
<FloatButton label="Create" icon={<PlusIcon />} actions={[
{ id: 'doc', label: 'Document', icon: <FileIcon />, onPress: newDoc },
{ id: 'task', label: 'Task', icon: <CheckIcon />, onPress: newTask },
]} />
- Without
fixedit’sabsolute, so the parent needsrelative.position:bottom-right(default),bottom-left,top-right. labelis required: it names the icon-only button and is its tooltip.- With
actions,onPressis ignored: the button toggles the dial (aria-expanded) and turns its icon 45°, so a plus reads as a close mark. - The dial closes on Escape (focus returns to the main button), an outside click, or a pick. The main button comes first in tab order, then the mini-buttons.
Example source · show· hide
import { FloatButton } from './float-button'
const I = ({ d }: { d: string }) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden><path d={d} /></svg>
const Stage = ({ children }: { children: React.ReactNode }) => <div className="relative h-72 w-96 overflow-hidden rounded-xl border border-border bg-surface-muted">{children}</div>
export const styles = {
Single: () => <Stage><FloatButton label="New message" icon={<I d="M12 5v14M5 12h14" />} /></Stage>,
'Speed dial': () => <Stage><FloatButton label="Create" icon={<I d="M12 5v14M5 12h14" />} actions={[{ id: 'doc', label: 'Document', icon: <I d="M14 2H6v20h12V6zM14 2v4h4" /> }, { id: 'img', label: 'Image', icon: <I d="M3 3h18v18H3zM8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4M21 15l-5-5L5 21" /> }, { id: 'task', label: 'Task', icon: <I d="m5 12 5 5L20 7" /> }]} /></Stage>,
}Source: packages/ui/src/float-button/float-button.tsx
Catalog
- Category
- inputs
- Priority
- Extra
- Primitive
- composed
- React Aria
- Button
- Base UI
- Button