Button
πDark Mode Compatible
An interactive action element with a two-dimensional variant system (appearance x variant) for flexible visual styling and semantic meaning.
Overviewβ
Use Button when you need:
- A primary or secondary call-to-action in forms, dialogs, or pages
- Destructive actions with clear danger styling
- Success confirmations or informational actions with semantic colors
- Navigation elements styled as buttons (via polymorphic
as="a") - Icon-only actions in compact toolbars
- Loading states with a built-in spinner
Live demoInteractive
Anatomyβ
The Button component is a single interactive element with optional icons and loading state:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Button β
β βββββββββ βββββββββββββββββββ βββββββββ β
β β Icon β β Button Text β β Icon β β
β β Left β β (children) β β Right β β
β β (opt) β β β β (opt) β β
β βββββββββ βββββββββββββββββββ βββββββββ β
β β
β Loading spinner replaces iconLeft when loading β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Parts:
- Container: single
buttonoraelement (controlled byas) - Icon Left (optional)
- Text Content (optional for icon-only buttons)
- Icon Right (optional)
- Loading Spinner (replaces icon left when
loadingis true)
Usageβ
import { Button } from '@grasdouble/lufa_design-system';
export function ButtonExamples() {
return (
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
<Button>Click me</Button>
<Button appearance="solid" variant="primary">
Save Changes
</Button>
<Button appearance="outline" variant="secondary">
Cancel
</Button>
<Button appearance="solid" variant="danger" iconLeft="trash">
Delete
</Button>
<Button appearance="solid" variant="primary" loading>
Saving...
</Button>
<Button as="a" href="/home" appearance="ghost" variant="neutral">
Go Home
</Button>
<Button iconLeft="search" aria-label="Search" />
</div>
);
}
Propsβ
| Prop | Type | Default | Description |
|---|---|---|---|
appearance | 'solid' | 'outline' | 'ghost' | 'solid' | Visual style (filled, border-only, or minimal) |
type | 'button' | 'submit' | 'reset' | 'button' | Native HTML button type |
variant | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'neutral' | 'primary' | Semantic color variant |
size | 'sm' | 'md' | 'lg' | 'md' | Button size |
radius | 'none' | 'sm' | 'base' | 'md' | 'full' | 'base' | Border radius |
iconLeft | IconName | undefined | Icon to display on the left side |
iconRight | IconName | undefined | Icon to display on the right side |
loading | boolean | false | Loading state - shows spinner and disables button |
disabled | boolean | false | Disabled state - prevents interaction |
fullWidth | boolean | false | Makes button stretch to 100% of container width |
as | 'button' | 'a' | 'button' | HTML element to render (polymorphic) |
children | ReactNode | undefined | Button text content (optional for icon-only buttons) |
className | string | undefined | Additional CSS classes |
Also supports all standard HTML attributes for the underlying element:
- When
as="button": allbuttonattributes (onClick,name,value,form) - When
as="a": allaattributes (href,target,rel,download) - Common attributes:
id,aria-*,data-*,style,tabIndex,role
Accessibilityβ
- Provide
aria-labelfor icon-only buttons. - Set
type="submit"ortype="reset"explicitly for form actions; the safe default isbutton. - Use
as="a"withhreffor navigation actions. - Loading sets
aria-busyand disables interaction. - Focus indicators are provided via
:focus-visiblestyles.
import { Button } from '@grasdouble/lufa_design-system';
export function AccessibleButtons() {
return (
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
<Button iconLeft="search" aria-label="Search" />
<Button as="a" href="/dashboard">
Go to Dashboard
</Button>
<Button loading>Saving...</Button>
</div>
);
}
Theming & Tokensβ
Button uses design-system tokens for color, spacing, radius, and focus styles. Variants map to semantic color tokens, and sizes map to spacing and typography tokens. Adjust tokens in your theme to change appearance consistently across all variants.
Do / Donβtβ
Do
- Use
appearance="solid"withvariant="primary"for the most important action on a page. - Use
appearance="outline"orappearance="ghost"for secondary actions. - Use
variant="danger"for destructive actions. - Provide descriptive labels for all buttons.
- Use
loadingduring async operations.
Don't
- Don't use multiple primary solid buttons on the same page.
- Don't use
variant="danger"for non-destructive actions. - Don't create icon-only buttons without
aria-label. - Don't disable buttons without explaining why.
- Don't use
as="a"withouthref.
Related Componentsβ
- Icon - Icons used within buttons (via
iconLeft,iconRightprops) - IconButton - Dedicated icon-only button component (if implemented)
- ButtonGroup - Group of related buttons with unified styling (if implemented)
- Link - Text link component for inline navigation
- Box - Layout container for spacing