Clickable button component with multiple variants, sizes, and loading states
Tags: component form action
Buttons trigger actions and navigation. They communicate what action will occur when clicked.
Import
<script>
import { Button } from '@classic-homes/theme-svelte';
</script>Basic Usage
<Button>Click Me</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link' |
'default' |
Visual style variant |
size |
'default' | 'sm' | 'md' | 'lg' | 'icon' |
'default' |
Size of the button |
type |
'button' | 'submit' | 'reset' |
'button' |
HTML button type |
href |
string |
- | If provided, renders as an anchor link |
disabled |
boolean |
false |
Disables the button |
loading |
boolean |
false |
Shows loading spinner |
loadingText |
string |
- | Text to show during loading (replaces children) |
class |
string |
- | Additional CSS classes |
onclick |
(e: MouseEvent) => void |
- | Click handler |
Variants
Default
The primary action button with solid background.
<Button variant="default">Default Button</Button>Secondary
Filled sage button for supporting actions such as "PDF" or "Filters": sage fill (secondary), white text, a 2px secondary-border ring, and the primary red fill on hover. Inside a Toolbar the ring takes the toolbar's light sage border automatically.
<Button variant="secondary">Secondary Button</Button>Destructive
For dangerous or irreversible actions like delete.
<Button variant="destructive">Delete</Button>Outline
Transparent button with a 2px sage (outline) border and normal foreground text; on hover it fills with the primary color and the border lightens (outline-hover). Use it for quiet actions like "Log in" or "Self Tour".
<Button variant="outline">Outline Button</Button>Ghost
Minimal button with no background until hovered.
<Button variant="ghost">Ghost Button</Button>Link
Styled as an inline text link.
<Button variant="link">Link Button</Button>Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="icon">
<svg><!-- icon --></svg>
</Button>| Size | Height | Padding |
|---|---|---|
sm |
36px (h-9) | 12px (px-3) |
default |
40px (h-10) | 16px (px-4) |
md |
40px (h-10) | 16px (px-4) |
lg |
44px (h-11) | 32px (px-8) |
icon |
40px (h-10) | Square (w-10) |
States
Disabled
<Button disabled>Disabled</Button>Disabled buttons have reduced opacity and ignore pointer events.
Loading
Shows a spinner and optionally replaces the text:
<Button loading>Submit</Button>
<Button loading loadingText="Saving...">Save</Button>When loading:
- Button is automatically disabled
- Spinner animation appears
aria-busy="true"is set for accessibility
As Link
Provide an href to render as an anchor element:
<Button href="/dashboard">Go to Dashboard</Button>
<Button href="https://example.com" target="_blank">External Link</Button>With Icons
Add icons alongside text using the default gap styling:
<Button>
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
Add Item
</Button>Icon-Only Button
Use size="icon" for square icon buttons:
<Button size="icon" variant="ghost" aria-label="Settings">
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</Button>Always provide an aria-label for icon-only buttons to ensure screen reader users understand the action.
Form Submission
Use type="submit" within forms:
<form onsubmit={handleSubmit}>
<Button type="submit">Submit Form</Button>
</form>Accessibility
The Button component includes these accessibility features:
- Full keyboard navigation (Tab, Enter, Space)
- Visible focus ring using
focus-visible aria-disabledset when disabled or loadingaria-busyset during loading state- Maintains color contrast ratios
Examples
Button Group
<div class="flex gap-2">
<Button variant="outline">Cancel</Button>
<Button>Save Changes</Button>
</div>Full Width Button
<Button class="w-full">Full Width Button</Button>Async Action
<script>
let loading = $state(false);
async function handleSave() {
loading = true;
try {
await saveData();
} finally {
loading = false;
}
}
</script>
<Button {loading} loadingText="Saving..." onclick={handleSave}>Save</Button>