calcom/cal.com
ui
Purpose
packages/ui is Cal.diy's design system — the React components that the web app, embeds, atoms, and the marketing site share. It is intentionally lightweight: it ships components, not opinions about data fetching or state management.
Directory layout
ui/
├── classNames.ts # `cn()` utility (clsx + tailwind-merge style)
├── components/ # ~50 component groups (button, form, dialog, ...)
├── styles/ # Tailwind layer + design tokens
├── scripts/ # Build helpers
├── tsconfig.json
├── package.json
└── .gitignorecomponents/ is the majority of the code. Each subdirectory is a single component or a small family (e.g., components/form/, components/button/, components/dialog/).
Conventions
- Direct imports.
AGENTS.mdmandatesimport { Button } from "@calcom/ui/components/button"instead of importing from@calcom/ui(no barrel files). The package intentionally has no top-levelindex.tsre-export. - Tailwind — every component is styled with Tailwind classes. The
cn()helper inclassNames.tsmerges classes safely. - Accessibility — components use Radix UI primitives where possible (Dialog, Tooltip, Popover, Select).
- Server / client — components are
"use client"by default unless they are pure presentational.
Highlighted components (selection)
| Component | Path | Purpose |
|---|---|---|
Button |
packages/ui/components/button/Button.tsx |
Primary action component, with variants and asChild support |
Form family |
packages/ui/components/form/ |
Inputs, labels, validation hooks tied to react-hook-form |
Dialog |
packages/ui/components/dialog/ |
Radix-backed modal dialog |
Tooltip |
packages/ui/components/tooltip/ |
Radix tooltip + project-specific styling |
Avatar |
packages/ui/components/avatar/ |
Initials fallback + image loader |
Toast |
packages/ui/components/toast/ |
Notification toasts |
Editor |
packages/ui/components/editor/ |
Lexical-based rich text editor used in event-type description |
Calendar |
packages/ui/components/calendar/ |
Visual calendar grid (not the federation logic — that's in features/calendars) |
Skeleton |
packages/ui/components/skeleton/ |
Loading placeholders |
EmptyState |
packages/ui/components/empty-state/ |
Generic empty-state shell |
The full list is too long to enumerate; browse packages/ui/components/ for the canonical inventory.
Integration points
apps/web— imports components everywhere via@calcom/ui/components/...packages/features/*/components/— feature-specific UI built on top of@calcom/uipackages/platform/atoms— Platform atoms reuse many@calcom/uicomponents, although they ship their own bundle independentlypackages/embeds/embed-react— embeds reuse a subset
How it works
graph LR
Tailwind[Tailwind tokens in styles/] --> Components[components/*]
Components --> Web[apps/web]
Components --> Features[packages/features]
Components --> Atoms[packages/platform/atoms]The package is designed to be tree-shakeable. Because consumers import from precise paths (components/button), bundlers can drop unused components from the final build.
Entry points for modification
- Adding a component: create
packages/ui/components/<group>/<Component>.tsxwith a*.stories.tsx(if Storybook is in use locally) and a co-located test. No barrel index. - Theming / tokens: edit
packages/ui/styles/. Tokens propagate to every consumer because Tailwind is configured at the workspace root. - Breaking a component API: usages live in
apps/web/,packages/features/, andpackages/platform/atoms. Runyarn type-checkafter the change to surface every consumer.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.