Button
Primary actions. 7 variants × 3 sizes × 6 states.
import { Button } from "@/components/ui/button";
export default function Example() {
return <Button>Order Darjeeling tea</Button>;
}
Installation
$ npx uix-ui@latest add buttonThis copies the file into components/ui/button.tsx in your project. npx shadcn@latest add @uix/button works too.
Usage
import { Button } from "@/components/ui/button";
<Button>Order Darjeeling tea</Button>
Examples
Variants
import { Button } from "@/components/ui/button";
export default function Example() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button variant="primary">Order now</Button>
<Button variant="secondary">Save for later</Button>
<Button variant="soft">Gift wrap</Button>
<Button variant="outline">View menu</Button>
<Button variant="ghost">Skip</Button>
<Button variant="destructive">Cancel order</Button>
<Button variant="link">Track parcel</Button>
</div>
);
}
Sizes
import { Button } from "@/components/ui/button";
export default function Example() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
);
}
With icons, avatar and count
import { ArrowRight, Plus } from "@/components/ui/icons";
import { Avatar } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
export default function Example() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button leadingIcon={<Plus />}>Add to cart</Button>
<Button variant="outline" trailingIcon={<ArrowRight />}>Checkout</Button>
<Button variant="soft" badge={3}>Cart</Button>
<Button variant="outline" avatar={<Avatar size="xs" initials="NJ" />}>Nusrat Jahan</Button>
</div>
);
}
Loading and disabled
import * as React from "react";
import { Button } from "@/components/ui/button";
export default function Example() {
const [busy, setBusy] = React.useState(false);
return (
<div className="flex flex-wrap items-center gap-3">
<Button loading={busy} onClick={() => { setBusy(true); setTimeout(() => setBusy(false), 1800); }}>{busy ? "Placing order" : "Place order"}</Button>
<Button disabled>Out of stock</Button>
<Button variant="outline" disabled>Sold out</Button>
</div>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | primary | secondary | soft | outline | ghost | destructive | link | "primary" | |
size | sm | md | lg | "md" | |
leadingIcon | React.ReactNode | – | Icon before the label. |
trailingIcon | React.ReactNode | – | Icon after the label. |
avatar | React.ReactNode | – | Avatar before the label (for example <Avatar size="xs" initials="AB" />). |
badge | React.ReactNode | – | Count pill after the label. |
leadingDivider | boolean | false | Hairline between the avatar / icon and the label. |
trailingDivider | boolean | false | Hairline between the label and the badge / icon. |
loading | boolean | false | Shows a spinner before the content, dims the label and blocks clicks. |
showLabel | boolean | true | False hides the label visually (it stays the accessible name): an icon-only button. |
Everything else is passed to the root element, so className, aria-* and event handlers work as usual.
Dependencies
Installed for you by the CLI.
class-variance-authorityclsxtailwind-merge
lib/utils.ts