Button
A pressable control that performs an action. Native on every platform; shared intent, tokens, and naming.
Installation
npx felicityui add button --platform reactUsage
import { Button } from "@/components/ui/button"
<Button>Button</Button>Use Button for actions. Do not use it for navigation that should be a link on the web, or for a control that only reveals UI without performing work — those belong to later overlay primitives.
When to use
- Commit a form, confirm a dialog, or start an asynchronous job.
- Icon-only toolbars: use
IconButton(React) orsize: iconwith an accessibility label on native platforms.
When not to use
- In-content navigation on the web (
<a>/Link). - A row in a list that navigates — use the platform's list/navigation primitives.
Default
Primary call to action. Uses color.action.primary.
Secondary
High-emphasis alternative on the inverse surface.
Outline
Low emphasis with a border.
Ghost
Tertiary, no fill until hover or press.
Destructive
Dangerous or irreversible action.
Size
Use the size prop to change control height.
Icon Button
Square icon-only control. Requires an accessible name. On React that is size=icon via IconButton.
Link Button
Looks like a text link. It is still a button, not a navigation link.
Segmented Button
Mutually exclusive options. Use ButtonGroup with segmented. React uses pressed; SwiftUI and Compose use selected.
Button Group
Related actions. Prefer the Button Group catalog item for separators, text addons, and orientation.
Loading
Busy state. The control is not operable and announces busy to assistive tech.
Disabled
Not operable. Reduced opacity.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | primary | secondary | outline | ghost | destructive | link | primary | Visual emphasis. |
| size | sm | md | lg | icon | md | Control height. icon is square, for Icon Button. |
| disabled | boolean | false | Prevents interaction. |
| loading | boolean | false | Shows a pending state and prevents interaction. |
| pressed | boolean | false | Selected state for a segment. Sets aria-pressed on React. |
| selected | boolean | false | Selected state for a segment. Native equivalent of React pressed. |
| segmented | boolean | false | On ButtonGroup: attach child buttons into one segmented control. |
| className | string | — | Additional classes. |
| label | String / @Composable () -> Unit / View | — | Visible label. Required unless an accessible name is provided for icon-only. |
Accessibility
WCAG 2.2 AA
- Must be exposed as a button, not a clickable
div. - Visible focus indicator using the focus ring token.
- Disabled and loading states are not in the tab order as an operable control (disabled) or announce busy (loading).
- Name is the visible text, or an accessible name for icon-only.
- Touch target at least
24×24 CSS pixels(WCAG 2.2Target Size) and preferably44×44on touch platforms. - Honor
prefers-reduced-motionfor loading indicators.
Platform notes
React
Renders a native HTML button. No overlay, no router integration. Icon-only use the size=icon variant (Icon Button).
Server Componentcompatible. No client JavaScript is required.- Prefer
type="button"inside forms unless the control submits.
SwiftUI
SwiftUI Button. Destructive maps to Role.destructive. Hits the standard iOS minimum touch target.
- Respects
Dynamic Typeand the system color scheme. VoiceOverreads the title; icon-only buttons require anaccessibilityLabel.- Requires Xcode 15+ / iOS 17+. Add generated files to the Xcode target.
- Disable with
.disabled(_:). Segment selection uses selected: true.
Compose
Composable button using FelicityUI tokens for color, shape, and height. Interaction follows Material press/ripple conventions without adopting Material color roles.
TalkBackuses the text orcontentDescription.- Minimum height follows
size.control.*tokens (32dpsmall,40dpmedium,48dplarge). - Material 3 may still enforce a
48dpminimum touch target around small buttons. - selected marks a segment.
FelicityButtonGroup(segmented = true)clips and strokes as one control.