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

Spinner

An indicator that can be used to show a loading state.

Playground

—className
—className
Usage
Import Spinner from the design system. It renders the Phosphor SpinnerIcon with role="status" and aria-label="Loading", spinning at 1s per turn — a 16px icon that inherits the text color wherever it lands.
import { Spinner } from "@workspace/ui/components/spinner"

<Spinner />
Size
The default footprint is size-4 (16px). Override it with a size-* utility — classes merge through cn(), so yours wins over the base one.
<Spinner className="size-3" />
<Spinner className="size-4" />
<Spinner className="size-6" />
<Spinner className="size-8" />
Color
The spinner draws with currentColor — there is no color prop or token of its own. Set a text-* class on the spinner or on a parent and it follows.
<Spinner className="size-6 text-primary" />
<Spinner className="size-6 text-muted-foreground" />
<Spinner className="size-6 text-destructive" />
In Button
The spinner sizes itself like any button icon. Add data-icon="inline-start" so the button tightens its start padding, and disable the button while the action is pending.
<Button disabled size="sm">
  <Spinner data-icon="inline-start" />
  Loading...
</Button>
<Button variant="outline" disabled size="sm">
  <Spinner data-icon="inline-start" />
  Please wait
</Button>
<Button variant="secondary" disabled size="sm">
  <Spinner data-icon="inline-start" />
  Processing
</Button>
In Badge
Badge caps any SVG child at 12px, so the spinner needs no size class. The same data-icon="inline-start" attribute tightens the badge's start padding.
SyncingUpdatingProcessing
<Badge>
  <Spinner data-icon="inline-start" />
  Syncing
</Badge>
<Badge variant="secondary">
  <Spinner data-icon="inline-start" />
  Updating
</Badge>
<Badge variant="outline">
  <Spinner data-icon="inline-start" />
  Processing
</Badge>
In Input Group
Drop the spinner into an InputGroupAddon while a request is in flight — align="inline-end" for a compact input, or align="block-end" with a status label under a textarea.
Validating...
<InputGroup>
  <InputGroupInput placeholder="Send a message..." disabled />
  <InputGroupAddon align="inline-end">
    <Spinner />
  </InputGroupAddon>
</InputGroup>

<InputGroup>
  <InputGroupTextarea placeholder="Send a message..." disabled />
  <InputGroupAddon align="block-end">
    <Spinner /> Validating...
    <InputGroupButton className="ms-auto" variant="default">
      <ArrowUpIcon />
      <span className="sr-only">Send</span>
    </InputGroupButton>
  </InputGroupAddon>
</InputGroup>
In Empty State
For a full-surface pending state, put the spinner in an Empty media slot — the icon variant frames it in a muted 40px tile while the title and description explain the wait.
Processing your request
Please wait while we process your request. Do not refresh the page.
<Empty className="w-full">
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <Spinner />
    </EmptyMedia>
    <EmptyTitle>Processing your request</EmptyTitle>
    <EmptyDescription>
      Please wait while we process your request. Do not refresh the page.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <Button variant="outline" size="sm">
      Cancel
    </Button>
  </EmptyContent>
</Empty>
API Reference
Spinner renders a single SVG and accepts every SVG attribute. It has no variants — restyle via className, or target data-slot="spinner" from a parent. Override aria-label to localize the announced text.
ComponentPropDefault
SpinnerclassName?: string—
Spinneraria-label?: string"Loading"
<Spinner data-slot="spinner" role="status" />

Tokens used

2 design tokens consumed by the Spinner component.

  • --spacing

    Spacing unit (4px)

    size-4
  • --animate-spin

    Spin (1s linear infinite)

    animate-spin