Components Actions
Button
StableTriggers an action, with six variants, four sizes and a loading state.
Use Button for actions that change something: saving, submitting, opening a dialog. Use Link for navigation that only moves the user elsewhere. Keep one primary button per view so the main action is unambiguous.
Overview
import { Button } from '@bindshq/stance-react';
export function Basic() {
return <Button>Save changes</Button>;
}Light, dark and high contrast
Every Stance component is designed and tested in all three appearance modes.
Import
import { Button } from '@bindshq/stance-react';Platforms
Button has native counterparts. They share Stance tokens and intent, and use each platform’s own controls and conventions. The live previews on this page are the web implementation.
import { Button } from '@bindshq/stance-react';Playground
<Button>Save changes</Button>Examples
Variants
Emphasis from strongest to weakest. Danger is reserved for destructive actions.
import { Button } from '@bindshq/stance-react';
export function Variants() {
return (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Delete</Button>
<Button variant="link">Link</Button>
</div>
);
}Sizes
Control heights of 24, 32, 40 and 48px align with inputs of the same size.
import { Button } from '@bindshq/stance-react';
export function Sizes() {
return (
<div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 12 }}>
<Button size="xs">Extra small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
);
}import { Button, Icon } from '@bindshq/stance-react';
export function WithIcons() {
return (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
<Button leadingIcon={<Icon name="plus" />}>New template</Button>
<Button variant="outline" trailingIcon={<Icon name="arrow-right" />}>
Continue
</Button>
</div>
);
}Loading
Loading keeps the button focusable and announces aria-busy while blocking repeat clicks.
import { Button } from '@bindshq/stance-react';
export function Loading() {
return (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
<Button loading>Save</Button>
<Button loading loadingText="Publishing…" variant="outline">
Publish
</Button>
</div>
);
}Pill shape
Fully rounded ends for marketing calls to action.
import { Button, Icon } from '@bindshq/stance-react';
export function Pill() {
return (
<Button shape="pill" size="lg" trailingIcon={<Icon name="arrow-right" />}>
Let’s talk
</Button>
);
}As a link
Use asChild to give a router link button styling while keeping link semantics.
import { Button } from '@bindshq/stance-react';
export function AsLink() {
return (
<Button asChild variant="outline">
<a href="#docs">Read the docs</a>
</Button>
);
}API reference
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'link' | 'primary' | Visual emphasis. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Control height: 24, 32, 40 or 48px. |
shape | 'default' | 'pill' | 'default' | Pill gives fully rounded ends. |
loading | boolean | false | Shows a spinner, sets aria-busy and blocks clicks. |
loadingText | ReactNode | None | Replaces the label while loading. |
leadingIcon | ReactNode | None | Rendered before the label. |
trailingIcon | ReactNode | None | Rendered after the label. |
fullWidth | boolean | false | Fill the container width. |
asChild | boolean | false | Render the child element with button styles. |
...props | ButtonHTMLAttributes | None | All native button attributes. type defaults to "button". |
Accessibility
- Renders a native <button>, so it is focusable and activates with Enter and Space without extra code.
- type defaults to "button" to prevent accidental form submission; pass type="submit" explicitly.
- Icon-only actions should use IconButton, which requires an accessible label.
- Loading sets aria-busy and aria-disabled but keeps focus, so keyboard users do not lose their place.
- Focus is shown with a 2px ring (3px in high contrast) offset from the button edge.
Keyboard
| Keys | Action |
|---|---|
| Enter | Activates the button. |
| Space | Activates the button. |
Usage guidelines
Do
- Start labels with a verb: “Save changes”, “Invite member”.
- Use one primary button per view.
Don’t
- Use a button to navigate between pages; use Link.
- Disable a submit button to signal errors; show the errors instead.