Button
Atomshadcn/ui, restyled with tokensStarts an action. One primary per view; everything else is secondary or quieter.
components/atoms/button.tsx- Use it for
- Submitting a form, confirming, opening a dialog — anything that does something on this page.
- Not for
- Going somewhere else. That is a Link, or a Button with asChild around one.
States
Usage
import { Button } from '@/components/atoms/button';
<Button variant="primary" type="submit" loading={isSaving}>
Save & Continue
</Button>
// A link that looks like an action keeps its link semantics:
<Button asChild variant="soft">
<Link href="/ui-showcase">See the components</Link>
</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'primary' | 'outlined' | 'secondary' | 'soft' | 'ghost' | 'danger' | 'ghost-danger' | 'secondary' | How loud the action is. Danger is for actions that destroy something; ghost-danger is the quiet one, such as removing a row. |
| size | 'sm' | 'md' | 'lg' | 'icon' | 'md' | Padding and type size. Icon is a round button holding only an icon, and needs aria-label. |
| loading | boolean | false | Shows a spinner, sets aria-busy and blocks presses. The label stays. |
| asChild | boolean | false | Paints its single child (usually a Link) as a button instead of rendering a <button>. |
| prefixIcon | ReactNode | — | An icon before the label, such as Google’s mark on “Continue with Google”. Decorative; the spinner replaces it while loading. |
| type | 'button' | 'submit' | 'reset' | 'button' | Defaults to button so it never submits a form by accident. |
| ...rest | ComponentProps<'button'> | — | Every native button prop, including ref and aria-*. |
Accessibility
- Reached with Tab, pressed with Enter or Space.
- Named by its text. An icon-only button needs aria-label.
- While loading it is announced as busy and keeps its name.