Design System

Core components

The first component layer. Every example below renders the production component straight from @/design-system — no mock-ups, no screenshots. Toggle the theme in the header to check both palettes.

Button

The single action control of the system. Visual weight is chosen with variant, scale with size — there is no per-variant component.

import { Button } from "@/design-system";

Variants

Sizes

States

Hover and focus are interactive — hover with the pointer, then Tab through the row.

With icons

Accessibility

  • Renders a real <button> with type="button" by default; asChild keeps semantics when rendering a link.
  • Visible 2px focus ring from the focus border token, never removed on keyboard focus.
  • Loading sets aria-busy, blocks interaction and announces the loading label to screen readers.
  • Disabled uses the disabled attribute, so it is skipped in the tab order.

IconButton

A control whose only content is an icon. The label prop is required so the button always has an accessible name.

import { IconButton } from "@/design-system";

Variants

Sizes and states

Accessibility

  • label is applied as aria-label and title — an icon-only control can never ship unnamed.
  • Square tap area of at least 32px, 40px at the default medium size.
  • Loading swaps the icon for a spinner and keeps the accessible name.

Input

Single-line text field with label, helper text, validation messaging and optional leading/trailing icons.

import { Input } from "@/design-system";

Anatomy and states

As it appears on your ID.

Email verified.

Generated automatically.

Sizes

Shape

default (8px control radius), rounded for search-style fields, squared inside bordered groups.

Value alignment

Right alignment suits numeric and currency fields.

Accessibility

  • Label is always wired to the control; an id is generated when none is supplied.
  • Helper and validation text are linked with aria-describedby.
  • Errors set aria-invalid and render role="alert" text with an icon — never colour alone.
  • Required renders a visual marker plus a screen-reader-only "(required)".

Textarea

Multi-line text field sharing the Input chrome, with an optional character counter.

import { Textarea } from "@/design-system";

States

Plain text, no links.

0 / 160 characters

Saved.

Accessibility

  • The counter is linked with aria-describedby and updates in a polite live region.
  • Error text uses role="alert" and an icon alongside the error border.
  • Resizes vertically only, so layout cannot be broken horizontally.

Select

Single-choice picker built on the Radix Select primitive, with the same field anatomy as Input.

import { Select } from "@/design-system";

States

Where your team is based.

Accessibility

  • Full keyboard support from Radix: arrows, Home/End, typeahead, Escape to dismiss.
  • Trigger exposes the open state; the checked item carries a check glyph as well as colour.
  • Disabled options are skipped by keyboard navigation.

Checkbox

Tri-state selection control for forms: unchecked, checked and indeterminate.

import { Checkbox } from "@/design-system";

States

Cycles indeterminate → checked → indeterminate.

Send me a weekly summary.

Accessibility

  • Radix Checkbox provides role, checked state and Space activation.
  • Selected and indeterminate states carry a glyph in addition to the primary fill.
  • Error state sets aria-invalid and shows an icon-led message.

Radio

Mutually exclusive choice within a RadioGroup. RadioField adds the standard label, helper and error rhythm.

import { Radio, RadioField } from "@/design-system";

Group

Plan(required)
One workspace, up to 3 people.
Unlimited workspaces.
SSO and audit logs.
No longer available.

You can change this at any time.

Billing cycle

Accessibility

  • Radix RadioGroup manages roving tabindex — the group is one tab stop, arrows move between options.
  • Each option label is wired to its control; descriptions use aria-describedby.
  • Group-level errors are announced and marked with aria-invalid.

Switch

Immediate on/off toggle for settings. Use Checkbox inside forms that are explicitly submitted.

import { Switch } from "@/design-system";

States

Product updates and security alerts.

Accessibility

  • Radix Switch exposes role="switch" with checked state and Space/Enter activation.
  • Label is associated with the control and remains clickable.
  • Thumb movement uses the motion tokens, which collapse under prefers-reduced-motion.

Badge

Compact, non-interactive status or metadata label. Subtle is the default treatment; solid is reserved for stronger emphasis. A badge never looks or behaves like a button — no border, shadow or hover state.

import { Badge } from "@/design-system";

Subtle — Default

NeutralBrandAccentSuccessWarningErrorInfo

Solid — Strong emphasis

NeutralBrandAccentSuccessWarningErrorInfo

With icon — subtle

ApprovedNeeds reviewFailedIn progress

With dot

A tinted dot for compact status lists; the label still carries the meaning.

SuccessWarningDangerInfoPrimarySecondary

With avatar

OROlivia RhyeMGMartin Guptil

Removable

The only interactive affordance a badge may carry.

Willow HouseContractor

With icon — solid

ApprovedNeeds reviewFailedInfo

Sizes — small (24px) and medium (28px)

SmallMediumSmallMedium

Shape

Pill is the status default; rounded and square suit counts and dense table cells.

PillRoundedSquare12

Accessibility

  • Status is carried by the label text — and optionally an icon — not by colour alone.
  • Non-interactive by design: use Button for anything clickable.
  • Both appearances meet AA contrast in light and dark themes.

Avatar

Represents a person or entity with an image, initials, or a neutral glyph fallback.

import { Avatar } from "@/design-system";

Sizes

JCJCJCJCJC

Image, initials, fallback

JCCDUser

Pill shape

Widens to carry a short label next to the initials.

JCJane CooperCTCare team

Accessibility

  • The image uses the name as alt text; the glyph fallback exposes the name to screen readers.
  • Purely decorative in lists — pair with a visible name for identification.

Tooltip

Supplementary text attached to a control. Never the only place essential information lives.

import { Tooltip, TooltipProvider } from "@/design-system";

Usage

Tab to either control to open the tooltip from the keyboard.

Accessibility

  • Radix Tooltip opens on hover and on keyboard focus, and dismisses with Escape.
  • The trigger keeps its own accessible name; the tooltip only supplements it.
  • Requires a TooltipProvider ancestor so timing and single-open behaviour are shared.

Divider

A one-pixel rule separating content, using the semantic border tokens.

import { Divider } from "@/design-system";

Horizontal

Vertical

Overview
Activity
Settings