Button

A versatile button component.

Props

A Button component has the following properties:

PropRequiredDescription
typenoDefault type: button.
hrefnoRender button as anchor when present.
variantnofilled (default) or outlined.
onclicknoOptional click handler.
classnoAdditional classes.

Snippets

NameRequiredDescription
childrennoOmit for an icon-only button.
iconnoSnippet to add an icon.

Examples

Default Button

This is the default button:

<script lang="ts">
	import { Button } from '$lib/components/index.js';

	let isSpinning = $state(false);

	function handleClick() {
		isSpinning = true;
		setTimeout(() => {
			isSpinning = false;
		}, 600);
	}
</script>

<Button onclick={handleClick} class={isSpinning ? 'spin' : ''}>Click me!</Button>

<style>
	:global(.spin) {
		animation: spin 0.6s ease-in-out;
	}

	@keyframes spin {
		to {
			transform: rotateZ(360deg);
		}
	}
</style>

This is a disabled default button:

<script lang="ts">
	import { Button } from '$lib/components/index.js';
</script>

<Button onclick={() => alert('Button clicked!')} disabled>I am disabled</Button>

Outlined Button

This is an outlined button:

<script lang="ts">
	import { Button } from '$lib/components/index.js';
</script>

<Button variant="outlined" onclick={() => alert('Button clicked!')}>Click me!</Button>

This is a disabled outlined button:

<script lang="ts">
	import { Button } from '$lib/components/index.js';
</script>

<Button variant="outlined" onclick={() => alert('Button clicked!')} disabled>I am disabled</Button>

Icon Button

You can add an icon to the button using the icon snippet:

<script lang="ts">
	import { Check, Save } from '@lucide/svelte';
	import { Button } from '$lib/components/index.js';

	let clicked = $state(false);

	function handleClick() {
		clicked = true;
		setTimeout(() => {
			clicked = false;
		}, 1000);
	}
</script>

<Button onclick={handleClick}>
	{#snippet icon()}
		{#if clicked}
			<Check />
		{:else}
			<Save />
		{/if}
	{/snippet}
	Save
</Button>

Icon-only Button

When only the icon snippet is provided (and children is omitted), the button is rendered in icon-only mode with a square shape:

<script lang="ts">
	import { Check, Save } from '@lucide/svelte';
	import { Button } from '$lib/components/index.js';

	let clicked = $state(false);

	function handleClick() {
		clicked = true;
		setTimeout(() => {
			clicked = false;
		}, 1000);
	}
</script>

<Button onclick={handleClick} aria-label="Save">
	{#snippet icon()}
		{#if clicked}
			<Check />
		{:else}
			<Save />
		{/if}
	{/snippet}
</Button>

Link Button

If the href prop is provided, the button will be rendered as an anchor:

<script lang="ts">
	import { House } from '@lucide/svelte';
	import { Button } from '$lib/components/index.js';
</script>

<Button href="/">
	{#snippet icon()}
		<House class="size-4"></House>
	{/snippet}
	Home
</Button>