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

Popover

Displays rich content in a portal, triggered by a button.

Playground

—side
—align
—sideOffset
—open
—modal
Usage
Popover wraps a PopoverTrigger and the PopoverContent it opens. The content renders in a portal, 288px wide (w-72) by default — override with className. PopoverHeader, PopoverTitle and PopoverDescription give the body its standard heading stack.
import {
  Popover,
  PopoverContent,
  PopoverDescription,
  PopoverHeader,
  PopoverTitle,
  PopoverTrigger,
} from "@workspace/ui/components/popover"

<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">Open popover</Button>
  </PopoverTrigger>
  <PopoverContent>
    <PopoverHeader>
      <PopoverTitle>Dimensions</PopoverTitle>
      <PopoverDescription>
        Set the dimensions for the layer.
      </PopoverDescription>
    </PopoverHeader>
  </PopoverContent>
</Popover>
Form
Unlike a tooltip, a popover holds interactive content — focus moves inside when it opens and Tab cycles through the controls. Compose the body from Field parts; the content's own gap-4 stacks the header and the field group.
<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">Open form</Button>
  </PopoverTrigger>
  <PopoverContent className="w-80" align="start">
    <PopoverHeader>
      <PopoverTitle>Dimensions</PopoverTitle>
      <PopoverDescription>
        Set the dimensions for the layer.
      </PopoverDescription>
    </PopoverHeader>
    <FieldGroup className="gap-3">
      <Field orientation="horizontal">
        <FieldLabel htmlFor="width">Width</FieldLabel>
        <Input id="width" defaultValue="100%" className="h-8 w-36" />
      </Field>
      <Field orientation="horizontal">
        <FieldLabel htmlFor="max-width">Max. width</FieldLabel>
        <Input id="max-width" defaultValue="300px" className="h-8 w-36" />
      </Field>
      <Field orientation="horizontal">
        <FieldLabel htmlFor="height">Height</FieldLabel>
        <Input id="height" defaultValue="25px" className="h-8 w-36" />
      </Field>
    </FieldGroup>
  </PopoverContent>
</Popover>
Alignment
align positions the content along the trigger's edge — start, center (the default) or end. It combines with side, and when there is not enough room Radix flips the popover to the opposite side automatically.
<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">Start</Button>
  </PopoverTrigger>
  <PopoverContent align="start" className="w-56">
    Aligned to the start of the trigger.
  </PopoverContent>
</Popover>
<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">Center</Button>
  </PopoverTrigger>
  <PopoverContent align="center" className="w-56">
    Centered on the trigger.
  </PopoverContent>
</Popover>
<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">End</Button>
  </PopoverTrigger>
  <PopoverContent align="end" className="w-56">
    Aligned to the end of the trigger.
  </PopoverContent>
</Popover>
RTL
The content inherits the document direction, and align is logical — start hugs the right edge of the trigger in RTL. side stays physical: "left" is the left regardless of direction.
<div dir="rtl">
  <Popover>
    <PopoverTrigger asChild>
      <Button variant="outline">افتح النافذة</Button>
    </PopoverTrigger>
    <PopoverContent align="start">
      <PopoverHeader>
        <PopoverTitle>الأبعاد</PopoverTitle>
        <PopoverDescription>حدد أبعاد الطبقة.</PopoverDescription>
      </PopoverHeader>
    </PopoverContent>
  </Popover>
</div>
Accessibility
The trigger is a button exposing aria-haspopup="dialog", aria-expanded and aria-controls; the content is a role="dialog" panel. Focus moves into the content on open and returns to the trigger on close. Escape or an outside interaction dismisses it. Both parts carry data-state="open|closed" for styling.
<button
  data-slot="popover-trigger"
  data-state="open"
  aria-haspopup="dialog"
  aria-expanded="true"
  aria-controls="radix-:r1:"
>
  Open popover
</button>
<div data-slot="popover-content" data-state="open" role="dialog" id="radix-:r1:">
  Popover content
</div>
API Reference
Every part wraps the matching Radix Popover primitive and accepts all of its props — open state on the Popover root, positioning on PopoverContent. The most used ones:
PartPropTypeDefault
Popoveropenboolean—
PopoverdefaultOpenbooleanfalse
PopoveronOpenChange(open: boolean) => void—
Popovermodalbooleanfalse
PopoverTriggerasChildbooleanfalse
PopoverContentside"top" | "right" | "bottom" | "left""bottom"
PopoverContentalign"start" | "center" | "end""center"
PopoverContentsideOffsetnumber4
<Popover data-slot="popover" />                  // Root — state container, renders nothing
<PopoverTrigger data-slot="popover-trigger" />   // <button>, toggles the popover
<PopoverAnchor data-slot="popover-anchor" />     // optional — position against this instead of the trigger
<PopoverContent data-slot="popover-content" />   // portaled panel (w-72, bg-popover)
<PopoverHeader data-slot="popover-header" />     // title + description stack
<PopoverTitle data-slot="popover-title" />
<PopoverDescription data-slot="popover-description" />

Tokens used

8 design tokens consumed by the Popover component.

  • --popover

    Popover

    bg-popover
  • --popover-foreground

    Popover Foreground

    text-popover-foreground
  • --foreground

    Foreground

    ring-foreground/10
  • --muted-foreground

    Muted Foreground

    text-muted-foreground
  • --font-weight-medium

    Font weight Medium (500)

    font-medium
  • --text-sm

    Text Small (14px)

    text-sm
  • --radius-md

    Radius 0.8× (8px)

    rounded-md
  • --spacing

    Spacing unit (4px)

    w-72p-4gap-4gap-1