Use one dominant button and demote secondary actions with lower emphasis variants.
Button
Triggers a single action. The hierarchy of variants guides attention to what matters most on a page.
Variants
Four visual styles, one hierarchy rule: only one primary button per section. Everything else supports it.
Primary — variant="solid" intent="primary"
Secondary — variant="outline" intent="secondary"
Ghost — variant="ghost"
Danger — variant="solid" intent="danger"
Icons
Buttons accept a leading icon, a trailing icon, both, or neither. Icon-only buttons need an ariaLabel.
Leading icon
Trailing icon
Icon only
Disabled
Parts
- .source-button Root interactive element
- .source-button-label Text label inside the button
- .source-button-icon Optional leading or trailing icon slot
-
.source-button-spinner
Loading spinner when
loadingis true
States
Design intent
A button answers the question "what can I do here?" without the user reading surrounding text. The variant communicates how important the action is — solid for the primary path, outline for secondary options, ghost for tertiary or contextual actions. Danger is reserved for destructive operations; never use it as an accent color.
Never have two solid buttons competing for attention in the same area. If a page section has multiple actions, one should be solid (or outline) and the rest should drop to ghost or link.
When to use
Prefer specific action text like "Save draft" or "Publish".
Use icons as support, not as the only way to understand the action.
Do not give equal visual weight to competing actions.
Avoid generic labels when the outcome could be ambiguous.
Never rely only on red color. Use explicit destructive wording.
Choosing the right variant
Icon placement
ariaLabel.Button props
Basic usage
import { Button } from '@pierredelattre/source-react';
// Primary
<Button intent="primary">Save changes</Button>
// Secondary
<Button intent="secondary" variant="outline">Cancel</Button>
// Ghost
<Button intent="secondary" variant="ghost">Dismiss</Button>
// Danger
<Button intent="danger">Delete account</Button>
// Danger outline
<Button intent="danger" variant="outline">Remove</Button>With icons
// Leading icon
<Button intent="primary" leadingIcon={<ArrowRightIcon />}>
Continue
</Button>
// Trailing icon
<Button intent="secondary" variant="outline" trailingIcon={<DownloadIcon />}>
Export
</Button>
// Icon only — ariaLabel required
<Button
intent="secondary"
variant="ghost"
ariaLabel="Close dialog"
leadingIcon={<Cross1Icon />}
/>Loading state
<Button intent="primary" loading={isSubmitting}>
Save changes
</Button>As link
<Button
href="https://github.com/pierredelattre/source-design-system"
external
variant="ghost"
intent="secondary"
>
Open repository
</Button>Component tokens
ARIA attributes
Keyboard support
Designer checklist
- Icon-only buttons have an
ariaLabelthat describes the action, not the icon. - Danger actions are always paired with a cancel path — never presented alone.
- Button labels are verbs that describe the outcome, not the mechanism ("Save changes" not "Submit").
- Touch targets are at least 44×44px — use
size="lg"on mobile or in tight contexts. - Loading state disables the button so the same form cannot be submitted twice.