Westy Design Systemv0.2.7
OverviewComponentsExamplesStorybook

Foundations

  • Typography
  • Colors
  • Spacing
  • Radius
  • Shadows
  • Icons

Components

  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Date Picker
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Menubar
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Questionnaire
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toggle
  • Toggle Group
  • Tooltip

Chat

  • Attachment
  • Bubble
  • Marker
  • Message
  • Message Scroller

Components

Button

Displays a button or a component that looks like a button.

Playground

—variant
—size
—label
—icon
—iconPosition
—disabled
—fullWidth
Usage
Import Button from the design system and pick a variant. The default variant renders the brand primary.
import { Button } from "@workspace/ui/components/button"

<Button variant="outline">Button</Button>
<Button variant="outline" size="icon" aria-label="Submit">
  <ArrowUpIcon />
</Button>
Cursor
Tailwind v4 switched buttons from cursor: pointer to cursor: default. The design system restores the pointer globally in globals.css, so buttons keep the pointer cursor with no per-app setup.
@layer base {
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}
Size
Use the size prop to change the size of the button. Every text size has a matching icon size that renders a square button.
<Button size="xs" variant="outline">Extra Small</Button>
<Button size="icon-xs" variant="outline" aria-label="Submit">
  <ArrowUpRightIcon />
</Button>

<Button size="sm" variant="outline">Small</Button>
<Button size="icon-sm" variant="outline" aria-label="Submit">
  <ArrowUpRightIcon />
</Button>

<Button variant="outline">Default</Button>
<Button size="icon" variant="outline" aria-label="Submit">
  <ArrowUpRightIcon />
</Button>

<Button size="lg" variant="outline">Large</Button>
<Button size="icon-lg" variant="outline" aria-label="Submit">
  <ArrowUpRightIcon />
</Button>
Default
<Button>Button</Button>
Outline
<Button variant="outline">Outline</Button>
Secondary
<Button variant="secondary">Secondary</Button>
Ghost
<Button variant="ghost">Ghost</Button>
Destructive
<Button variant="destructive">Destructive</Button>
Link
<Button variant="link">Link</Button>
Icon
Use an icon size and a single icon child for icon-only buttons. Always set aria-label.
<Button variant="outline" size="icon" aria-label="Update">
  <ArrowCircleUpIcon />
</Button>
With Icon
Add the data-icon="inline-start" or data-icon="inline-end" attribute to the icon for the correct spacing.
<Button variant="outline">
  <GitBranchIcon data-icon="inline-start" /> New Branch
</Button>
<Button variant="outline">
  Fork
  <GitForkIcon data-icon="inline-end" />
</Button>
Rounded
Use the rounded-full class to make the button rounded.
<Button className="rounded-full">Get Started</Button>
<Button
  variant="outline"
  size="icon"
  className="rounded-full"
  aria-label="Submit"
>
  <ArrowUpIcon />
</Button>
Spinner
Render a Spinner component inside the button to show a loading state. Remember to add the data-icon attribute to the spinner for the correct spacing.
<Button variant="outline" disabled>
  <Spinner data-icon="inline-start" />
  Generating
</Button>
<Button variant="secondary" disabled>
  Downloading
  <Spinner data-icon="inline-end" />
</Button>
Button Group
To combine related buttons, wrap them in the ButtonGroup component. See the Button Group page for the full API.
<ButtonGroup>
  <ButtonGroup>
    <Button variant="outline" size="icon" aria-label="Go Back">
      <ArrowLeftIcon />
    </Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button variant="outline">Archive</Button>
    <Button variant="outline">Report</Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button variant="outline">Snooze</Button>
    <Button variant="outline" size="icon" aria-label="More Options">
      <DotsThreeIcon />
    </Button>
  </ButtonGroup>
</ButtonGroup>
As Child
Use the asChild prop to make another component look like a button — the Radix Slot merges the button classes onto the child and keeps its semantics. Here's an example of a link that looks like a button.
Login
import Link from "next/link"

<Button asChild>
  <Link href="#">Login</Link>
</Button>
RTL
Buttons work in right-to-left layouts out of the box — the icon paddings use logical properties. Add rtl:rotate-180 to directional icons so arrows point the right way.
<div dir="rtl">
  <Button variant="outline">زر</Button>
  <Button variant="destructive">حذف</Button>
  <Button variant="outline">
    إرسال <ArrowRightIcon className="rtl:rotate-180" data-icon="inline-end" />
  </Button>
  <Button variant="outline" size="icon" aria-label="Add">
    <PlusIcon />
  </Button>
  <Button variant="secondary" disabled>
    <Spinner data-icon="inline-start" /> جاري التحميل
  </Button>
</div>
API Reference
Button wraps the native button element and accepts all of its props, plus the variant props below.
PropTypeDefault
variant"default" | "outline" | "ghost" | "destructive" | "secondary" | "link""default"
size"default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg""default"
asChildbooleanfalse

Tokens used

12 design tokens consumed by the Button component.

  • --primary

    Primary

    bg-primaryhover:bg-primary/80text-primary
  • --primary-foreground

    Primary Foreground

    text-primary-foreground
  • --secondary

    Secondary

    bg-secondary
  • --secondary-foreground

    Secondary Foreground

    text-secondary-foreground
  • --background

    Background

    bg-background
  • --foreground

    Foreground

    hover:text-foreground
  • --muted

    Muted

    hover:bg-muteddark:hover:bg-muted/50
  • --border

    Border

    border-border
  • --input

    Input

    dark:border-inputdark:bg-input/30dark:hover:bg-input/50
  • --destructive

    Destructive

    bg-destructive/10text-destructivehover:bg-destructive/20aria-invalid:border-destructive
  • --ring

    Ring

    focus-visible:border-ringfocus-visible:ring-ring/50
  • --radius-md

    Radius 0.8× (8px)

    rounded-mdrounded-[min(var(--radius-md),10px)]