Skip to content

Button

npm package: import it from 'flootlets'
bun add flootlets
Or copy it in with the shadcn CLI: import it from '@/components/ui/…'
npx shadcn@latest add https://dyeoh.github.io/flootlets/r/button.json

Both need Tailwind CSS v4; see Installation for the setup.

The variants and sizes are shadcn/ui’s. Use default for the one main action on a page, destructive for actions that delete or remove, and link for a button that reads as a link.

export default function ButtonVariants() {
return (
<>
<Button>Add to cart</Button>
<Button variant="secondary">Save for later</Button>
<Button variant="outline">View details</Button>
<Button variant="ghost">Cancel</Button>
<Button variant="destructive">Remove</Button>
<Button variant="link">Size guide</Button>
</>
);
}
export default function ButtonSizes() {
return (
<>
<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
</>
);
}

While loading, the button keeps its focus and width, shows a spinner, sets aria-busy and ignores clicks, so a double tap can’t pay twice.

import { createSignal } from 'solid-js';
// Press it: the button stays focused and keeps its width while busy.
export default function ButtonLoading() {
const [busy, setBusy] = createSignal(false);
const pay = () => {
setBusy(true);
setTimeout(() => setBusy(false), 2000);
};
return (
<Button loading={busy()} onClick={pay}>
Pay RM 29.20
</Button>
);
}

With href, Button renders a real <a>: it navigates without JavaScript and screen readers announce it as a link. A disabled link button drops its href but stays focusable.

export default function ButtonLinks() {
return (
<>
<Button href="#cart" variant="outline">
View cart
</Button>
<Button href="#checkout" disabled>
Checkout
</Button>
</>
);
}
Prop Type Default
variant 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' 'default'
size 'default' | 'sm' | 'lg' | 'icon' 'default' icon is square; give it an aria-label
loading boolean false Busy state; see above
fullWidth boolean false Fill the container’s width
href string Render a link instead of a button
type 'button' | 'submit' | 'reset' 'button' Set 'submit' explicitly for form submit buttons

Any other attribute (onClick, aria-*, class…) is passed to the element.

Pass Tailwind classes in class; they’re merged last with tailwind-merge, so class="h-12 rounded-full" replaces the size’s height and radius rather than fighting it. buttonVariants({ variant, size }) gives the same classes for other elements.

State: data-slot="button", data-variant, data-size, data-loading.

flootlets 0.2.3 · Changelog