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

Tooltip

A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.

Playground

—side
—align
—sideOffset
—children
—open
Usage
Import the Tooltip parts from the design system and wrap the trigger with asChild so the tooltip attaches to your own element. The showcase layout already mounts TooltipProvider, so tooltips work anywhere in the tree without extra setup.
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@workspace/ui/components/tooltip"

<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Hover</Button>
  </TooltipTrigger>
  <TooltipContent>Add to library</TooltipContent>
</Tooltip>
Side
Position the tooltip with the side prop on TooltipContent — top (the default), right, bottom or left. When there is not enough room, Radix flips the tooltip to the opposite side automatically.
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Top</Button>
  </TooltipTrigger>
  <TooltipContent side="top">Tooltip on top</TooltipContent>
</Tooltip>
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Right</Button>
  </TooltipTrigger>
  <TooltipContent side="right">Tooltip on the right</TooltipContent>
</Tooltip>
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Bottom</Button>
  </TooltipTrigger>
  <TooltipContent side="bottom">Tooltip on the bottom</TooltipContent>
</Tooltip>
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Left</Button>
  </TooltipTrigger>
  <TooltipContent side="left">Tooltip on the left</TooltipContent>
</Tooltip>
With Keyboard Shortcut
Drop a Kbd inside TooltipContent to document a shortcut. The content restyles the kbd for the inverted surface and trims its own end padding via has-data-[slot=kbd]:pe-1.5, so no extra classes are needed.
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">
      <FloppyDiskIcon data-icon="inline-start" />
      Save
    </Button>
  </TooltipTrigger>
  <TooltipContent>
    Save changes <Kbd>⌘S</Kbd>
  </TooltipContent>
</Tooltip>
Icon Button
Tooltips are the standard way to label icon-only buttons — the visible text lives in the tooltip while aria-label covers assistive technology.
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline" size="icon" aria-label="Add to library">
      <PlusIcon />
    </Button>
  </TooltipTrigger>
  <TooltipContent>Add to library</TooltipContent>
</Tooltip>
Disabled Button
Disabled elements do not emit pointer or focus events, so a tooltip on a bare disabled button never opens. Wrap the button in a focusable span and let the wrapper be the trigger — a good place to explain why the action is unavailable.
<Tooltip>
  <TooltipTrigger asChild>
    <span tabIndex={0}>
      <Button variant="outline" disabled>
        Publish
      </Button>
    </span>
  </TooltipTrigger>
  <TooltipContent>Fix the validation errors first</TooltipContent>
</Tooltip>
RTL
Tooltips need no extra classes in right-to-left layouts — the kbd padding uses logical properties, so spacing follows the document direction. Note that side is physical: "left" stays on the left regardless of direction.
<div dir="rtl">
  <Tooltip>
    <TooltipTrigger asChild>
      <Button variant="outline">حفظ</Button>
    </TooltipTrigger>
    <TooltipContent>
      حفظ التغييرات <Kbd>⌘S</Kbd>
    </TooltipContent>
  </Tooltip>
</div>
Provider
Tooltips require a single TooltipProvider near the root of the app — it shares timing state so pointing from one trigger to the next opens instantly. This design system sets delayDuration to 0 by default. The showcase already mounts it in app/layout.tsx; a new consumer app sets it up once:
import { TooltipProvider } from "@workspace/ui/components/tooltip"

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <TooltipProvider>{children}</TooltipProvider>
      </body>
    </html>
  )
}
API Reference
The parts wrap the Radix Tooltip primitive and accept all of its props. The most used ones are below — the open state lives on the Tooltip root, positioning on TooltipContent, and timing on the TooltipProvider.
PartPropTypeDefault
Tooltipopenboolean—
TooltipdefaultOpenbooleanfalse
TooltiponOpenChange(open: boolean) => void—
TooltipContentside"top" | "right" | "bottom" | "left""top"
TooltipContentalign"start" | "center" | "end""center"
TooltipContentsideOffsetnumber0
TooltipProviderdelayDurationnumber0

Tokens used

7 design tokens consumed by the Tooltip component.

  • --foreground

    Foreground

    bg-foregroundfill-foreground
  • --background

    Background

    text-background
  • --text-xs

    Text Extra Small (12px)

    text-xs
  • --radius-md

    Radius 0.8× (8px)

    rounded-md
  • --radius-sm

    Radius 0.6× (6px)

    **:data-[slot=kbd]:rounded-sm
  • --container-xs

    Container XS (320px)

    max-w-xs
  • --spacing

    Spacing unit (4px)

    px-3py-1.5gap-1.5size-2.5