Button

An accessible action primitive with solid, outline, ghost, and destructive variants, plus sizes, icons, and loading state.

Loading preview

Examples

Practical examples and common states for the same installable component.

Secondary

Quiet supporting action that still reads as clickable.

examples/button-secondary.tsx
import { Button } from "@/components/wensity/button";
export function ButtonSecondary() {
return <Button variant="secondary">Save draft</Button>;
}

White

Bright CTA reserved for dark heroes or one-action moments.

examples/button-white.tsx
import { IconArrowRight } from "@tabler/icons-react";
import { Button } from "@/components/wensity/button";
export function ButtonWhite() {
return (
<Button variant="white" rightIcon={<IconArrowRight />} rightIconMotion="arrow">
Launch demo
</Button>
);
}

Destructive

Danger action for deletion or irreversible changes.

examples/button-destructive.tsx
import { IconTrash } from "@tabler/icons-react";
import { Button } from "@/components/wensity/button";
export function ButtonDestructive() {
return (
<Button variant="destructive" leftIcon={<IconTrash />} leftIconMotion="trash">
Delete project
</Button>
);
}

Icons

Optional left and right icon slots without extra wrappers.

examples/button-icons.tsx
import { IconDownload, IconMail } from "@tabler/icons-react";
import { Button } from "@/components/wensity/button";
export function ButtonIcons() {
return (
<div className="flex items-center gap-3">
<Button leftIcon={<IconMail />} leftIconMotion="mail">
Email team
</Button>
<Button variant="outline" rightIcon={<IconDownload />} rightIconMotion="download">
Download
</Button>
</div>
);
}

Loading

Built-in loading state disables the action and keeps width stable.

examples/button-loading.tsx
import { Button } from "@/components/wensity/button";
export function ButtonLoading() {
return <Button loading>Saving changes</Button>;
}

Ghost

Toolbar and dense UI action with minimal chrome.

examples/button-ghost.tsx
import { Button } from "@/components/wensity/button";
export function ButtonGhost() {
return <Button variant="ghost">Cancel</Button>;
}

Disabled

Disabled buttons keep layout stable while clearly dropping emphasis.

examples/button-disabled.tsx
import { Button } from "@/components/wensity/button";
export function ButtonDisabled() {
return (
<div className="flex items-center gap-3">
<Button disabled>Disabled</Button>
<Button disabled variant="outline">
Disabled
</Button>
</div>
);
}

Props

PropTypeDefaultDescription
variant"default" | "secondary" | "outline" | "ghost" | "white" | "destructive" | "link""default"Visual weight of the button. white is for dark heroes; link renders as inline text.
size"sm" | "md" | "lg" | "icon""md"Control height and padding. icon renders a square button with no gap.
loadingbooleanfalseSwaps the content for a spinner and blocks interaction while an action is in flight.
disabledbooleanfalseDisables the button and drops it to 45% opacity.
focusableWhenDisabledboolean-Keeps the button reachable by keyboard while disabled, so screen readers still announce it.
leftIconReact.ReactNode-Icon rendered before the label. Sized to 16px automatically.
rightIconReact.ReactNode-Icon rendered after the label. Sized to 16px automatically.
leftIconMotion"trash" | "mail"-Animates the left icon on hover with a named motion recipe.
rightIconMotion"arrow" | "download"-Animates the right icon on hover with a named motion recipe.
asChildbooleanfalseRenders the child element instead of a button, keeping styles. Use for links.