Button
In the appFive variants, five sizes, one component. The outline is the default because it is what the app reaches for; navy is for the one primary action on a screen.
@varick/ui/components/buttonAdded 26 Aug 2026
Usage
import { Button } from "@varick/ui/components/button";
export function Example() {
return (
<>
<Button variant="primary" onClick={run}>Run agent</Button>
<Button>Assign</Button>
</>
);
}Variants
Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="icon" aria-label="More"><DotsIcon /></Button>
<Button size="icon-sm" aria-label="More"><DotsIcon /></Button>With an icon
<Button variant="primary"><PlusIcon /> New agent</Button>
<Button>Export <ExternalIcon /></Button>Loading and disabled
<Button variant="primary" loading={isRunning} onClick={run}>
{isRunning ? "Running" : "Run agent"}
</Button>
<Button disabled>Disabled</Button>API reference
Every component also accepts className and the native props of its root element.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'outline' | 'primary' | 'ghost' | 'destructive' | 'link' | 'outline' | Emphasis. One primary per view. |
| size | 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm' | 'md' | Height 28, 32, 36; icon squares 30 and 24. |
| loading | boolean | false | Shows a spinner, sets aria-busy and disables the button. |
| disabled | boolean | false | Dims to 50% and drops pointer events. |
| ...props | ComponentProps<'button'> | Every native button prop passes through. type defaults to "button". |
Accessibility
- Icon-only buttons take an aria-label; the icon alone is never the name.
- Focus is the global 2px accent outline, offset 2px, on :focus-visible only.
- A loading button stays in the tab order and announces aria-busy rather than disappearing.
Styles
The CSS as it appears in the app. The live component above is the same values as Tailwind classes.
.btn-primary {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--canvas);
color: #FFFFFF;
font-size: 13px;
font-weight: 500;
border-radius: 4px;
padding: 8px 14px;
transition: opacity 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.btn-primary:hover { opacity: 0.92; }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-ghost {
display: inline-flex;
align-items: center;
gap: 6px;
border: 1px solid var(--hairline);
border-radius: 4px;
padding: 7px 12px;
font-size: 12.5px;
font-weight: 500;
color: var(--fg-high);
background: #FFFFFF;
}
.btn-ghost:hover { border-color: var(--hairline-hover); background: var(--fill-soft); }
.btn-primary:active, .btn-ghost:active { transform: scale(0.97); }