- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
Default is the primary action. Outline and ghost are quieter. Destructive is for a harmful action. Link looks like text.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonDemo() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
<Button>Book test</Button>
<Button variant="outline">Details</Button>
<Button variant="secondary">Later</Button>
<Button variant="ghost">Skip</Button>
<Button variant="destructive">Delete</Button>
<Button variant="link">Learn more</Button>
<Button variant="invert">Invert</Button>
</div>
)
}
Usage
Use a button for an action on the current page: save, open, delete, or continue. If the control navigates to another URL, render it as a link. One primary button per section is enough. The rest should be outline, secondary, or ghost.
Import it from @workspace/ui/components/button.
Anatomy
- Button —
variantisdefault,outline,outlineglass,secondary,ghost,destructive,link, orinvert.sizeissm,default,lg,icon-sm,icon, oricon-lg. - buttonVariants — The class function behind Button. Use it to style another element, such as a link, as a button.
Notes
- Icon-only buttons need an
aria-label. The icon is not a name. - Put
data-icon="inline-start"ordata-icon="inline-end"on an icon so the padding stays even. - Disabled buttons stay visible. Do not hide an action the reader is not allowed to take. Explain why nearby if it is not obvious.
- To make a button navigate, set
nativeButton={false}and pass an anchor throughrender.
Examples
Outline
A quieter action next to a primary one. outlineglass is the same with a soft inner shadow.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonOutline() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
<Button variant="outline">View report</Button>
<Button variant="outlineglass">View report</Button>
</div>
)
}
Secondary
For actions that matter less than the primary one.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonSecondary() {
return <Button variant="secondary">Remind me later</Button>
}
Ghost
No border or fill until hover. Use in toolbars and dense rows.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonGhost() {
return <Button variant="ghost">Skip</Button>
}
Destructive
For actions that delete or cannot be undone.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonDestructive() {
return <Button variant="destructive">Delete report</Button>
}
Link
Looks like text. Use for low-weight navigation.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonLink() {
return <Button variant="link">Read the guide</Button>
}
As a link
For navigation, render an a through render and set nativeButton={false}.
"use client"
import { ArrowUpRightIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
export function ButtonAsLink() {
return (
<Button
nativeButton={false}
render={<a href="https://predict.fit" target="_blank" rel="noreferrer" />}
>
Book a test
<ArrowUpRightIcon data-icon="inline-end" />
</Button>
)
}
Invert
Uses the foreground colour as the fill.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonInvert() {
return <Button variant="invert">Get started</Button>
}
Sizes
sm, default, and lg, plus a matching icon size for each.
"use client"
import { PlusIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
export function ButtonSizes() {
return (
<div className="grid gap-4">
<div className="flex flex-wrap items-center justify-center gap-3">
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
</div>
<div className="flex flex-wrap items-center justify-center gap-3">
<Button size="icon-sm" aria-label="Add">
<PlusIcon />
</Button>
<Button size="icon" aria-label="Add">
<PlusIcon />
</Button>
<Button size="icon-lg" aria-label="Add">
<PlusIcon />
</Button>
</div>
</div>
)
}
Icon
An icon-only button. Always give it an aria-label.
"use client"
import { DownloadIcon, PlusIcon, ShareIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
export function ButtonIcon() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
<Button size="icon" aria-label="Add marker">
<PlusIcon />
</Button>
<Button size="icon" variant="outline" aria-label="Download report">
<DownloadIcon />
</Button>
<Button size="icon" variant="ghost" aria-label="Share">
<ShareIcon />
</Button>
</div>
)
}
With icon
Mark the icon with data-icon so the padding adjusts on that side.
"use client"
import { ArrowRightIcon, DownloadIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
export function ButtonWithIcon() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
<Button size="sm">
<DownloadIcon data-icon="inline-start" />
Download
</Button>
<Button variant="outline">
<DownloadIcon data-icon="inline-start" />
Download
</Button>
<Button>
Continue
<ArrowRightIcon data-icon="inline-end" />
</Button>
<Button variant="secondary" size="lg">
<DownloadIcon data-icon="inline-start" />
Download
</Button>
<Button size="lg">
Continue
<ArrowRightIcon data-icon="inline-end" />
</Button>
</div>
)
}
Disabled
Disabled buttons fade and ignore clicks.
"use client"
import { Button } from "@workspace/ui/components/button"
export function ButtonDisabled() {
return (
<div className="flex flex-wrap items-center justify-center gap-3">
<Button disabled>Book test</Button>
<Button variant="outline" disabled>
Details
</Button>
</div>
)
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
Button
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default", "outline", "outlineglass", "secondary", "ghost", "destructive", "link", or "invert" | default | Emphasis of the action. |
size | "sm", "default", "lg", "icon-sm", "icon", or "icon-lg" | default | Height and padding. |
disabled | boolean | false | Blocks the action and dims the button. |
nativeButton | boolean | true | Set false when render is not a button, such as a link. |
render | ReactElement | — | Element to render instead of a button. |
className | string | — | Classes merged onto the element. |