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

Calendar

A date field component that lets users browse months and select single dates, multiple dates or ranges. Built on React DayPicker.

Playground

September 2026
SuMoTuWeThFrSa
—mode
—captionLayout
—numberOfMonths
—buttonVariant
—showOutsideDays
—showWeekNumber
Usage
Set mode to pick the selection behavior. Selection is uncontrolled by default — pass selected and onSelect to control it from your own state, as in the Date picker example below.
August 2026
SuMoTuWeThFrSa
import { Calendar } from "@workspace/ui/components/calendar"

<Calendar mode="single" className="rounded-lg border" />
Range
mode="range" selects a start and end date; the days in between get the muted range styling. numberOfMonths lays out extra months side by side, which pairs naturally with range selection.
August 2026
SuMoTuWeThFrSa
September 2026
SuMoTuWeThFrSa
<Calendar
  mode="range"
  numberOfMonths={2}
  className="rounded-lg border"
/>
Month and year dropdowns
captionLayout="dropdown" replaces the caption label with native month and year selects — handy for far-away dates like birthdays. dropdown-months and dropdown-years switch only one side. Bound the year list with startMonth and endMonth.
Aug2026August 2026
SuMoTuWeThFrSa
<Calendar
  mode="single"
  captionLayout="dropdown"
  startMonth={new Date(1990, 0)}
  endMonth={new Date(2030, 11)}
  className="rounded-lg border"
/>
Disabled dates
The disabled prop accepts a matcher or an array of matchers: specific dates, a { before, after } window, or dayOfWeek indices. Disabled days keep their slot in the grid but cannot be focused or selected — here weekends are off-limits.
August 2026
SuMoTuWeThFrSa
<Calendar
  mode="single"
  disabled={{ dayOfWeek: [0, 6] }}
  className="rounded-lg border"
/>
Week numbers
showWeekNumber prepends an ISO week-number column rendered in text-muted-foreground. showOutsideDays (on by default) fills the leading and trailing cells with the neighboring months.
August 2026
SuMoTuWeThFrSa
31
32
33
34
35
36
<Calendar
  mode="single"
  showWeekNumber
  className="rounded-lg border"
/>
Cell size
Every cell, nav button and caption row is sized by the --cell-size CSS variable (default --spacing(8)), and cell corners by --cell-radius. Override them with arbitrary-property classes to scale the whole calendar without touching individual parts.
August 2026
SuMoTuWeThFrSa
<Calendar
  mode="single"
  className="rounded-lg border [--cell-size:--spacing(10)]"
/>
Date picker
Compose Calendar inside a Popover for the classic date-picker pattern: a trigger button shows the current value, and onSelect stores the date and closes the popover. Strip the popover padding with w-auto p-0 — the calendar already carries its own.
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<Date | undefined>(undefined)

<Popover open={open} onOpenChange={setOpen}>
  <PopoverTrigger asChild>
    <Button variant="outline" className="w-56 justify-start font-normal">
      <CalendarBlankIcon className="text-muted-foreground" />
      {date
        ? date.toLocaleDateString("en-US", { dateStyle: "long" })
        : <span className="text-muted-foreground">Pick a date</span>}
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-0" align="start">
    <Calendar
      mode="single"
      selected={date}
      captionLayout="dropdown"
      onSelect={(selected) => {
        setDate(selected)
        setOpen(false)
      }}
    />
  </PopoverContent>
</Popover>
RTL
Pass a locale from react-day-picker/locale together with dir="rtl". The month grid, range styling and nav chevrons all mirror via logical properties — the previous / next buttons swap direction without extra classes.
سبتمبر 2026
سبتأحداثنينثلاثاءأربعاءخميسجمعة
import { ar } from "react-day-picker/locale"

<Calendar mode="single" locale={ar} dir="rtl" className="rounded-lg border" />
Accessibility
DayPicker complies with WCAG 2.1 AA: the month renders as a grid with labeled columns, each day is a real button announcing its full date, and the nav buttons carry accessible labels. Arrow keys move focus between days, PageUp / PageDown change month (with Shift, year), and Home / End jump to the week bounds. Pass autoFocus to move focus into the grid when the calendar appears inside a popover.
<PopoverContent className="w-auto p-0" align="start">
  <Calendar mode="single" autoFocus />
</PopoverContent>
API Reference
Calendar wraps React DayPicker with Westy styling and forwards every DayPicker prop — the table lists the ones you'll reach for most; see the React DayPicker docs for the full surface. CalendarDayButton renders each day cell and is exported for custom components.DayButton overrides.
ComponentPropDefault
Calendarmode?: "single" | "multiple" | "range"—
Calendarselected?, onSelect?: controlled selection for the active mode—
CalendarcaptionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years""label"
CalendarnumberOfMonths?: number1
CalendarshowOutsideDays?: booleantrue
CalendarshowWeekNumber?: booleanfalse
Calendardisabled?: Matcher | Matcher[]—
CalendarbuttonVariant?: Button variant for the nav buttons"ghost"
Calendarlocale?: Locale, dir?: "ltr" | "rtl"—
<Calendar data-slot="calendar" />
<CalendarDayButton
  data-day
  data-selected-single
  data-range-start
  data-range-middle
  data-range-end
/>

Tokens used

14 design tokens consumed by the Calendar component.

  • --background

    Background

    bg-background
  • --primary

    Primary

    bg-primary
  • --primary-foreground

    Primary Foreground

    text-primary-foreground
  • --muted

    Muted

    bg-muted
  • --foreground

    Foreground

    text-foreground
  • --muted-foreground

    Muted Foreground

    text-muted-foreground
  • --accent

    Accent

    hover:bg-accent
  • --accent-foreground

    Accent Foreground

    hover:text-accent-foreground
  • --popover

    Popover

    bg-popover
  • --ring

    Ring

    ring-ring/50border-ring
  • --radius-md

    Radius Medium (via --cell-radius)

    rounded-(--cell-radius)
  • --spacing

    Spacing unit (4px, via --cell-size)

    size-(--cell-size)p-3gap-4gap-1.5
  • --text-sm

    Text Small (14px)

    text-sm
  • --font-weight-medium

    Font weight Medium (500)

    font-medium