Button
Trigger actions and events with accessible, styled buttons. Supports variants, colors, icons, loading states, active state, avatar, and can render as links.
Playground
Experiment with different props in real-time.
Basic Usage
Import and use the Button component with a label prop.
<script lang="ts">
import { Button } from 'sv5ui';
</script>
<Button label="Button" />Variants
6 visual styles for different levels of emphasis.
<Button variant="solid" label="Solid" />
<Button variant="outline" label="Outline" />
<Button variant="soft" label="Soft" />
<Button variant="subtle" label="Subtle" />
<Button variant="ghost" label="Ghost" />
<Button variant="link" label="Link" />Colors
8 semantic color schemes.
<Button color="primary" label="Primary" />
<Button color="secondary" label="Secondary" />
<Button color="tertiary" label="Tertiary" />
<Button color="success" label="Success" />
<Button color="warning" label="Warning" />
<Button color="error" label="Error" />
<Button color="info" label="Info" />
<Button color="surface" label="Surface" />Sizes
5 sizes from extra small to extra large.
<Button size="xs" label="Extra Small" />
<Button size="sm" label="Small" />
<Button size="md" label="Medium" />
<Button size="lg" label="Large" />
<Button size="xl" label="Extra Large" />Icon Only
Use the icon prop for icon-only buttons. Add square for equal width and height.
<!-- Icon only -->
<Button icon="lucide:plus" />
<!-- Icon only with square aspect ratio -->
<Button icon="lucide:settings" square />
<Button icon="lucide:heart" variant="outline" square />
<Button icon="lucide:trash-2" variant="soft" color="error" square />Leading & Trailing Icons
Add icons before or after the label with leadingIcon and trailingIcon. Use trailing to move a single icon to the trailing side.
<!-- Leading icon -->
<Button leadingIcon="lucide:download" label="Download" />
<!-- Trailing icon -->
<Button trailingIcon="lucide:arrow-right" label="Next" />
<!-- Both icons -->
<Button leadingIcon="lucide:mail" trailingIcon="lucide:send" label="Send" />
<!-- Trailing prop: moves single icon to trailing side -->
<Button icon="lucide:arrow-right" label="Continue" trailing />Loading
Show a spinner and disable interaction with the loading prop. Customize the spinner icon with loadingIcon. The spinner takes the leading side, or the trailing side with trailing, and is shown instead of an icon or a slot there.
<!-- Default loading -->
<Button label="Loading" loading />
<!-- Custom loading icon -->
<Button label="Refreshing" loading loadingIcon="lucide:refresh-cw" />
<!-- Loading with variant -->
<Button label="Saving" loading variant="outline" />
<Button label="Loading" loading variant="soft" />Loading Auto
Use loadingAuto to automatically show a loading spinner while the onclick handler's promise is pending.
<script lang="ts">
import { Button } from 'sv5ui';
function handleSave() {
return new Promise((resolve) => setTimeout(resolve, 2000));
}
</script>
<!-- Automatically shows loading while the promise is pending -->
<Button label="Save Changes" loadingAuto onclick={handleSave} />
<Button label="Submit" loadingAuto onclick={handleSave} variant="outline" />Disabled
Disable the button to prevent interaction.
<Button label="Disabled" disabled />
<Button label="Disabled" disabled variant="outline" />
<Button label="Disabled" disabled variant="soft" />Block (Full Width)
Stretch the button to full width with the block prop.
<Button label="Full Width Button" block />
<Button label="Full Width Outline" variant="outline" block />
<Button label="Full Width Soft" variant="soft" block />Button Type
Set the HTML type attribute. Useful in forms for submit and reset behavior.
<form onsubmit|preventDefault={() => alert('Submitted!')}>
<Button type="submit" label="Submit" color="primary" />
<Button type="reset" label="Reset" variant="outline" color="surface" />
<Button type="button" label="Cancel" variant="ghost" />
</form>As Link
Pass an href prop to render as an anchor element. Use external to automatically add target="_blank" and rel="noopener noreferrer".
<!-- Internal link -->
<Button href="/docs" label="Go to Docs" />
<!-- External link with external prop -->
<Button href="https://github.com" external label="GitHub" leadingIcon="mdi:github" />
<!-- External adds target="_blank" and rel="noopener noreferrer" automatically -->Form & Anchor Attributes
Associate a submit button with a form by form id, bypass validation with formnovalidate, or turn a link button into a download with download.
<script lang="ts">
import { Button, FormField, Input } from 'sv5ui';
let email = $state('');
let message = $state('');
function handleSubmit(e: SubmitEvent) {
e.preventDefault();
message = email ? `Subscribed: ${email}` : 'Submitted without an email';
}
</script>
<!-- The form lives on its own; buttons are associated by id via `form` -->
<form id="newsletter" onsubmit={handleSubmit}>
<FormField label="Email">
<Input bind:value={email} name="email" type="email" required placeholder="you@example.com" />
</FormField>
</form>
<!-- Native button form attributes are now type-checked -->
<Button type="submit" form="newsletter" label="Subscribe" color="primary" />
<Button type="submit" form="newsletter" formnovalidate label="Submit anyway" variant="outline" color="surface" />
<!-- Typed <a> attributes apply when rendering as a link -->
<Button href="/favicon.png" download="sv5ui-icon.png" leadingIcon="lucide:download" label="Download" variant="soft" />Active State
Control active state manually with active, or let it auto-detect from the current URL when using href. Use exact for exact pathname matching. Customize the active appearance with activeColor, activeVariant, activeClass, and inactiveClass.
<!-- Manually set active state -->
<Button label="Active" active variant="ghost" activeVariant="soft" />
<!-- Active with different color -->
<Button label="Active" active activeColor="success" variant="ghost" />
<!-- Auto-detected from URL (with exact matching) -->
<Button href="/docs" label="Docs" variant="ghost" activeVariant="soft" activeColor="primary" exact />
<!-- Custom active/inactive classes -->
<Button
href="/docs"
label="Custom Active"
variant="ghost"
activeClass="font-bold ring-2 ring-primary"
inactiveClass="opacity-60"
/>Avatar
Display an avatar before the label with the avatar prop. It accepts AvatarProps.
<Button
avatar={{ src: 'https://i.pravatar.cc/32?u=1', alt: 'John' }}
label="John Doe"
/>
<Button
avatar={{ src: 'https://i.pravatar.cc/32?u=2', alt: 'Jane' }}
label="Jane Smith"
variant="outline"
/>
<Button
avatar={{ src: 'https://i.pravatar.cc/32?u=3', alt: 'User' }}
label="Profile"
trailingIcon="lucide:chevron-down"
variant="ghost"
/>Element Reference
Bind to the root DOM element with bind:ref for imperative access.
<script lang="ts">
import { Button } from 'sv5ui';
let buttonRef = $state<HTMLElement | null>(null);
function inspectButton() {
if (!buttonRef) return;
console.log('Tag:', buttonRef.tagName);
console.log('Size:', buttonRef.offsetWidth, 'x', buttonRef.offsetHeight);
console.log('Text:', buttonRef.textContent?.trim());
console.log('Classes:', buttonRef.className);
}
</script>
<Button bind:ref={buttonRef} label="Inspect Me" leadingIcon="lucide:search" onclick={inspectButton} />UI Slots
Use the ui prop to override classes on specific internal elements of the Button.
| Slot | Description |
|---|---|
base | Root button element - controls shape, padding, shadow, etc. |
label | Text label wrapper - controls font, spacing, text styles |
leadingIcon | Icon before the label - controls icon size, color, animation |
trailingIcon | Icon after the label - controls icon size, color, animation |
leadingAvatar | Avatar before the label - controls avatar wrapper styles |
<Button
label="Custom Styled"
leadingIcon="lucide:star"
ui={{
base: 'rounded-full shadow-lg',
label: 'font-bold tracking-wide',
leadingIcon: 'text-yellow-400'
}}
/><Button
label="Gradient Button"
leadingIcon="lucide:sparkles"
ui={{
base: 'bg-gradient-to-r from-purple-500 to-pink-500 border-none text-white hover:from-purple-600 hover:to-pink-600',
leadingIcon: 'animate-pulse'
}}
/>Snippets
Use snippets to fully replace the leading or trailing content with custom markup.
| Snippet | Replaces | Description |
|---|---|---|
children | label | Custom label content - use for rich text, inline elements, etc. |
leadingSlot | leadingIcon / avatar | Custom content before the label - replaces icon and avatar. The loading spinner is shown instead of it |
trailingSlot | trailingIcon | Custom content after the label - replaces trailing icon. With trailing set, the loading spinner is shown instead of it |
<Button variant="outline" color="primary">
{#snippet leadingSlot()}
<div class="flex h-5 w-5 items-center justify-center rounded-full bg-primary">
<span class="text-[10px] font-bold text-on-primary">AI</span>
</div>
{/snippet}
Ask Claude
{#snippet trailingSlot()}
<Kbd value="⌘K" size="sm" />
{/snippet}
</Button><Button variant="soft" color="success">
{#snippet leadingSlot()}
<span class="relative flex h-2.5 w-2.5">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-success opacity-75"></span>
<span class="relative inline-flex h-2.5 w-2.5 rounded-full bg-success"></span>
</span>
{/snippet}
Online
</Button>Props
| Prop | Type | Default |
|---|---|---|
variant | 'solid' | 'outline' | 'soft' | 'subtle' | 'ghost' | 'link' | 'solid' |
color | 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error' | 'info' | 'surface' | 'primary' |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
label | string | - |
icon | string | - |
leadingIcon | string | - |
trailingIcon | string | - |
trailing | boolean | false |
loading | boolean | false |
loadingAuto | boolean | false |
loadingIcon | string | 'lucide:loader-circle' |
disabled | boolean | false |
block | boolean | false |
square | boolean | false |
href | string | - |
type | 'button' | 'submit' | 'reset' | 'button' |
external | boolean | false |
active | boolean | - |
exact | boolean | false |
activeColor | ColorType | - |
activeVariant | VariantType | - |
activeClass | string | - |
inactiveClass | string | - |
avatar | AvatarProps | - |
ref | HTMLElement | null | null |
class | string | - |
ui | Record<Slot, Class> | - |