Button
The main button, with solid, outline and ghost styles, sizes, loading and icon slots.
Installation
npx axiom add buttonpnpm dlx axiom add buttonyarn dlx axiom add buttonbun x axiom add buttonAlso copies: tappable, slot, text, icon.
Usage
import { Button } from '@/components/ui/button';
<Button onPress={save}>Save</Button>
<Button variant="outline">Cancel</Button>
<Button variant="ghost" size="sm">Skip</Button>
<Button loading>Saving</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The label. Keep it to a short verb: “Save”, “Continue”. |
variant | 'solid' | 'outline' | 'ghost' | 'destructive' | 'solid' | Visual weight. solid for the main action of the screen, outline for a secondary action next to it, ghost for a low-emphasis action like “Skip”, destructive (red) for an irreversible action like “Delete”. |
size | 'sm' | 'md' | 'lg' | 'md' | Minimum height from the control size tokens: 32, 44 or 52pt. Grows with larger system text. sm still gets a 44pt touch area through Tappable. |
onPress | () => void | — | Called when the press ends on the button. Not called while loading or disabled. |
onLongPress | () => void | — | Called after the finger is held on the button. |
loading | boolean | false | Replaces the leading icon with a spinner and blocks presses. The button keeps its width so the layout doesn’t jump. |
disabled | boolean | false | Blocks presses, applies the disabled component tokens and sets accessibilityState.disabled. |
leadingIcon | IconName | — | Icon before the label, from your icon registry. Rendered with Icon, sized and colored for the button. |
trailingIcon | IconName | — | Icon after the label, typically a chevron or an external-link mark. |
fullWidth | boolean | false | Stretches the button to the width of its parent. Common for the main action at the bottom of a screen. |
asChild | boolean | false | Renders the child element instead of a pressable, and merges the button props and styles into it. See Slot. |
accessibilityLabel | string | label text | What screen readers announce. Required when the label alone is ambiguous. |
style | StyleProp<ViewStyle> | — | Extra styles for the container, applied after the variant styles. |
Use cases
Main action at the bottom of a form
One solid, full-width button pinned above the home indicator. It is the thing the screen exists for.
<Scaffold.Footer>
<Button size="lg" fullWidth onPress={signIn}>
Sign in
</Button>
<Button variant="ghost" fullWidth onPress={goToSignUp}>
Create an account
</Button>
</Scaffold.Footer>Waiting for a request
loading blocks double submits and shows progress without changing the size of the button.
<Button size="lg" fullWidth loading={isPaying} onPress={pay}>
{isPaying ? "Paying" : "Pay $88.90"}
</Button>Disabled until the form is valid
The button stays visible so the user knows what comes next, and turns active once the required fields are filled.
<Button fullWidth disabled={name.trim().length < 3} onPress={rename}>
Save
</Button>Primary and secondary side by side
Pair a solid button with an outline one when both choices are legitimate. Put the main action on the right.
<Card.Footer>
<Button variant="outline" style={{ flex: 1 }} onPress={decline}>
Decline
</Button>
<Button style={{ flex: 1 }} onPress={accept}>
Accept
</Button>
</Card.Footer>Label with an icon
An icon helps recognition when the action is frequent, like adding to a cart. Keep the label: the icon alone is an IconButton.
<Button size="lg" leadingIcon="cart" onPress={addToCart} style={{ flex: 1 }}>
Add to cart
</Button>Related
- IconButton
- ButtonGroup
- Slot, for
asChild - Tappable, for the press behavior