Actions Core Stable
Button
The foundational push-button: six variants, three sizes, a loading state, and a polymorphic href/anchor mode
Preview
svelte
<script lang="ts">
import { Button } from 'fancy-ui-svelte';
</script>
<Button />Installation
pnpm add fancy-ui-svelte
import { Button } from 'fancy-ui-svelte'
Usage
svelte
<script lang="ts">
import { Button } from 'fancy-ui-svelte';
</script>
<Button />Examples
Basic Usage
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
let count = $state(0);
</script>
<Button onclick={() => (count += 1)}>Clicked {count} {count === 1 ? "time" : "times"}</Button>Variants
All six visual treatments.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
import type { ButtonVariant } from "$lib/fancy-ui/button";
const variants: { variant: ButtonVariant; label: string }[] = [
{ variant: "primary", label: "Primary" },
{ variant: "secondary", label: "Secondary" },
{ variant: "outline", label: "Outline" },
{ variant: "ghost", label: "Ghost" },
{ variant: "accent", label: "Accent" },
{ variant: "destructive", label: "Destructive" },
];
</script>
<div class="flex flex-wrap items-center gap-3">
{#each variants as { variant, label } (variant)}
<Button {variant}>{label}</Button>
{/each}
</div>Sizes
Small, medium, and large.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
</script>
<div class="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>Loading State
Spinner in place of the icon, activation blocked, no dimming.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
let saving = $state(false);
async function save() {
saving = true;
await new Promise((resolve) => setTimeout(resolve, 1200));
saving = false;
}
</script>
<Button loading={saving} onclick={save}>
{saving ? "Saving..." : "Save changes"}
</Button>With Icons
iconStart and iconEnd snippets.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
import Plus from "@lucide/svelte/icons/plus";
import ArrowRight from "@lucide/svelte/icons/arrow-right";
</script>
{#snippet plusIcon()}
<Plus class="size-4" />
{/snippet}
{#snippet arrowIcon()}
<ArrowRight class="size-4" />
{/snippet}
<div class="flex flex-wrap items-center gap-3">
<Button iconStart={plusIcon}>New project</Button>
<Button variant="outline" iconEnd={arrowIcon}>Continue</Button>
</div>As Link
href renders an anchor instead of a button.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
</script>
<div class="flex flex-wrap items-center gap-3">
<Button href="/docs/components/button" variant="outline">Read the docs</Button>
<Button href="https://svelte.dev" target="_blank" variant="ghost">
Svelte docs (opens in a new tab)
</Button>
</div>Disabled State
Disabled on the button vs. the anchor — two different mechanisms.
svelte
<script lang="ts">
import { Button } from "$lib/fancy-ui/button";
</script>
<div class="flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-3">
<Button disabled>Disabled</Button>
<Button disabled variant="secondary">Disabled</Button>
<Button disabled variant="outline">Disabled</Button>
<Button disabled href="https://example.com">Disabled link</Button>
</div>
<p class="text-muted-foreground max-w-md text-sm leading-relaxed">
The button and the link are inert for different reasons. The button gets the real
<code class="text-xs">disabled</code> attribute; the link has no such state to lean on, so it
drops <code class="text-xs">href</code> entirely rather than relying on a click handler alone to stop
the navigation.
</p>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "outline" | "ghost" | "accent" | "destructive" | "primary" | Visual treatment |
size | "sm" | "md" | "lg" | "md" | Padding / font-size / radius scale |
type | "button" | "submit" | "reset" | "button" | Native type; ignored once href renders an anchor instead |
disabled | boolean | false | Greys the button out and blocks activation |
loading | boolean | false | Spinner in place of iconStart, aria-busy, inert to activation on both the button and anchor branch — does not dim the button |
href | string | - | Renders an <a> instead of a <button> when set |
target | string | - | Anchor target. "_blank" forces a safe rel |
rel | string | - | Anchor rel, widened rather than replaced when target="_blank" |
fullWidth | boolean | false | Stretches the button to its container's width |
label | string | - | Accessible name for a button whose content is icon-only |
onclick | (event: MouseEvent) => void | - | Fires on activation; never called while disabled or loading |
class | string | - | Additional CSS classes |
ref | HTMLButtonElement | HTMLAnchorElement | null | null | Bindable element reference |
sound | boolean | false | Plays the press cue on activation, once the user has enabled sound |
Slots
| Slot | Description |
|---|---|
children | The button's label / content |
iconStart | Rendered before the label; replaced by the spinner while loading |
iconEnd | Rendered after the label |
Links
Related components
Bu
ButtonGroup
Joins a row of adjacent actions into one seamless control — one border, one divider, no doubled edges
Actions Stable
Co
CopyButton
Button preset wired to the clipboard, swapping its icon and label to a success skin for a moment after a successful copy
Actions Stable
Ic
IconButton
Square or circular icon-only button built on Button, with a required accessible label
Actions Stable