Component reference
Button
Triggers one action, in one of six levels and three sizes.
Preview
Sizes, levels and unavailable states
The same action across three sizes and six levels: primary (black and white), secondary, quiet, accent soft fill (about current activity), stop (interrupting running work) and confirming a dangerous action. Buttons can be triggered from the keyboard; disabled controls skip Tab and produce no receipt.
render() {
const feedback = signal("Choose an action; the receipt here only happens locally.");
const actions = [
["primary", "Save changes"],
["outline", "View diff"],
["quiet", "Handle later"],
["danger", "Discard draft"],
["accent", "View progress"],
["stop", "Stop processing"],
] as const;
return (
<div className="workshop-stack workshop-constrained">
{(["small", "default", "large"] as const).map((size) => (
<Specimen
label={
{ small: "Compact toolbar", default: "Regular actions", large: "Priority actions" }[
size
]
}
align="start"
>
<div className="workshop-foundation-action-grid">
{actions.map(([variant, label]) => (
<Button
size={size}
variant={variant}
onClick={() => {
feedback.value = `Selected: ${label} (${size})`;
}}
>
{label}
</Button>
))}
<IconButton
size={size}
label={`${size} search`}
onClick={() => {
feedback.value = `Selected search (${size})`;
}}
>
<Icon name="search" />
</IconButton>
</div>
<div className="workshop-foundation-action-grid">
{actions.map(([variant, label]) => (
<Button size={size} variant={variant} disabled>
{label}
</Button>
))}
<IconButton size={size} label={`${size} search unavailable`} disabled>
<Icon name="search" />
</IconButton>
</div>
</Specimen>
))}
<Specimen label="Add entries" align="start">
<div className="workshop-row">
<AddButton
onClick={() => {
feedback.value = "Selected add";
}}
/>
<AddButton
variant="outline"
size="small"
onClick={() => {
feedback.value = "Selected add attachment";
}}
>
Add attachment
</AddButton>
<AddButton variant="quiet" size="large" disabled>
Add after the work completes
</AddButton>
</div>
</Specimen>
<Note role="status">{feedback}</Note>
</div>
);
}Installation
Usage
Taken from the examples on this page.
import { Button } from "meowtail";
<Button>Save changes</Button>Examples
The other stories that show this component.
Action hierarchy
Four real button variants plus the disabled state. Use Tab to see focus; disabled buttons cannot trigger actions.
render: () => (
<Measure width="narrow">
<Stack data-button-composition>
<Stack as="header" gap="compact">
<h2 style={{ margin: 0, fontSize: uiTokens.type.title, fontWeight: 600 }}>
Ready to deliver this change
</h2>
<span style={{ color: uiTokens.ink.secondary }}>
The primary action is clear and supporting actions step back. Every action is demoed
locally only.
</span>
</Stack>
<ActionRow>
<Button data-action="Saved the local sample.">Save changes</Button>
<Button variant="outline" data-action="Diff sample selected.">
View diff
</Button>
<Button variant="quiet" data-action="Continue editing.">
Continue editing
</Button>
</ActionRow>
<Stack as="section" gap="compact" aria-label="Actions not yet available">
<span style={{ color: uiTokens.ink.secondary, fontSize: uiTokens.type.caption }}>
No submission target selected yet
</span>
<ActionRow>
<Button disabled>Submit changes</Button>
<Button variant="outline" disabled>
Preview submission
</Button>
<Button variant="quiet" disabled>
Undo
</Button>
<Button variant="danger" disabled>
Delete
</Button>
</ActionRow>
</Stack>
<span
style={{ color: uiTokens.ink.secondary, fontSize: uiTokens.type.caption }}
role="status"
data-feedback
>
Choose an action to see immediate feedback.
</span>
<Inline as="section" gap="normal" aria-label="Discard draft demo">
<LayoutItem grow>
<Stack gap="compact">
<h2 style={{ margin: 0, fontSize: uiTokens.type.body, fontWeight: 600 }}>
Start over
</h2>
<span style={{ color: uiTokens.ink.secondary, fontSize: uiTokens.type.caption }}>
Only demonstrates discarding; no real file is deleted.
</span>
</Stack>
</LayoutItem>
<LayoutItem shrink={false}>
<Button
variant="danger"
data-action="Discarded the draft demo; no real file was deleted."
>
Discard local draft
</Button>
</LayoutItem>
</Inline>
</Stack>
</Measure>
)Sizes and long text
Small, default, and large sizes plus a longer action name to observe wrapping and hit areas on a narrow canvas.
render: () => (
<div className="workshop-stack workshop-constrained">
{(["small", "default", "large"] as const).map((size, index) => (
<Specimen
label={["Compact toolbar", "Regular actions", "Primary entry"][index]}
align="start"
>
<div className="workshop-row">
<Button size={size}>Save changes</Button>
<Button size={size} variant="outline">
View work outcomes
</Button>
<IconButton size={size} label={`${size} search`}>
<Icon name="search" />
</IconButton>
<IconButton size={size} label={`${size} close`} disabled>
<Icon name="x" />
</IconButton>
</div>
</Specimen>
))}
<Button size="large" variant="quiet">
View all work outcomes awaiting review in the current project
</Button>
</div>
)API reference
Props
| Prop | Type | Default |
|---|---|---|
variant | "primary" | "quiet" | "danger" | "outline" | "accent" | "stop" | "primary" |
size | "small" | "default" | "large" | "default" |
Also takes className, children and the attributes and events of its root element.
DOM parts
Registry
The component is registered as button in the meowtail component registry.