Button
Sizes sm/md/lg, five decorative tones, four appearances, start and end icons, full width, loading, a press ripple, and asChild for rendering as a link.
Tones
All five decorative tones, contained appearance. Button's tone is purely visual (ComponentTone) - it carries no status meaning, unlike Alert or Toast's semantic variant.
- Fuji UI's native visual language treats default as the main action tone - it resolves to the --fuji-default token. Pass tone to switch to one of the other four decorative tones (fire, water, forest, sun) - purely a visual choice, not a status signal.
Sizes
sm / md / lg, default tone.
Appearance
contained (the raised accent), bordered, dashed, and ghost - the same four appearance names every control shares. ghost casts no shadow, so it sits flat on the surface.
With icons
startIcon and endIcon place an icon before or after the label, spaced by the button's own gap.
- The label names the button, so the icon stays decorative - Lucide icons are aria-hidden unless you give them a label
- While loading, the spinner takes startIcon's place and endIcon is hidden
Full width
fullWidth stretches the button to the width of its container, for a single form action or a stacked mobile layout.
Icon button
Icon-only buttons across colors; aria-label is required at the type level.
Loading
- loading disables interaction and shows a spinner without changing the button's width
Disabled
Press ripple
A press grows a ripple from the point under the pointer. It holds while the pointer is down and fades on release, and each press gets its own wave.
- On by default for Button and IconButton; ripple={false} turns it off for one control
- Pointer presses only - Enter and Space activate the button without a wave
- Skipped entirely under prefers-reduced-motion: reduce
As a link
asChild moves Button's styling onto its single child, so a navigation target keeps real link behavior - middle-click, open in a new tab - while looking like a button.
- The child must forward its ref and spread the props it receives - a router's link component usually does
- disabled and loading become aria-disabled plus a click and keyboard guard, since an anchor has no disabled attribute
- The anchor does not pick up the browser's underline or link color
Button group
When to use
- Triggering an action in place - submitting a form, opening a dialog, running a command.
- Signalling hierarchy between actions on a surface: contained for the primary action, bordered for secondary, ghost for tertiary.
When not to use
- Navigating to another page or URL - use Link (or Button asChild wrapping an anchor) so middle-click, open-in-new-tab, and right-click all work.
- Toggling a single on/off value - use Switch or Checkbox, which announce their state.
- An icon-only control - use IconButton, which requires an accessible name at the type level.
Keyboard
Accessibility notes
- Every Button renders an explicit type (defaults to button, so it never submits a form by accident).
- loading sets aria-busy and disables the control while the async action runs, and the label width is held so the layout doesn't jump.
- Tone is decorative only - never rely on color alone to mark a destructive action; say so in the label.
- The press ripple is pointer-only decoration and is skipped under prefers-reduced-motion: reduce.
Common mistakes
- Using a Button for navigation - it breaks the browser affordances users expect from a link.
- Leaving out type="submit" on the button that submits a form - Button defaults to type="button", so pressing it does not submit.
Known limitations
- No built-in confirmation for destructive actions - pair it with an AlertDialog when the action can't be undone.
Related components
API reference
Visual treatment - filled, outlined, dashed, or bare.
Renders Button's styling onto its single child (ref- and prop-forwarding), e.g. a router link. Links lack native `disabled`, so `disabled`/`loading` use `aria-disabled` plus a click guard.
Icon rendered after the label.
Stretches to the width of its container.
Shows a spinner and disables interaction, keeping the button's width stable.
Plays a pointer-origin ripple on press. On by default, as part of how every button feels; pass `false` to suppress it. Does nothing under `prefers-reduced-motion: reduce`.
Control height and padding.
Icon rendered before the label.
Decorative color.
Also accepts everything from React.ButtonHTMLAttributes<HTMLButtonElement>.
Coding agents read this reference, with its examples, from the version your project has installed, through the Fuji UI MCP server. Set up your agent
