decocms / decocms-ui
Build or style React UI with the decocms product design system (@decocms/ui). Use when creating interfaces, pages, or components in a project that should look like decocms products, when the user mentions "design system", "@decocms/ui", "decocms style", or asks to make UI consistent with Studio. Covers installation, Tailwind v4 token setup, component inventory, and usage conventions.
decocms product design system (@decocms/ui)
React 19 components built on Radix primitives, styled with Tailwind CSS v4
semantic tokens. Light and dark themes work out of the box. Browse every
component and token at https://designsystem.decocms.com/
Install (new project)
bun add @decocms/ui react react-domRequirements: React 19 and Tailwind CSS v4 (bun add -d tailwindcss @tailwindcss/vite
plus the tailwindcss() plugin in vite.config.ts).
Make the design-system stylesheet the FIRST import of the app's CSS entry point —
it pulls in Tailwind itself, all tokens, and the bundled fonts (Inter + Commit Mono).
Do NOT also @import "tailwindcss" yourself:
@import "@decocms/ui/styles/global.css";Tailwind only scans app source by default; if the app's classes come exclusively
from @decocms/ui components this already works — the package declares its own@source.
Peers: install react-hook-form if you use the form component, and sonner
if you use toasts (sonner component). They are peers so the app and the design
system share one instance — never bundle a second copy.
Imports
No barrel export. Import each component from its subpath, extensionless:
import { Button } from "@decocms/ui/components/button";
import { Dialog, DialogContent, DialogTrigger } from "@decocms/ui/components/dialog";
import { cn } from "@decocms/ui/lib/utils";
import { useIsMobile } from "@decocms/ui/hooks/use-mobile";Exception — inside the decocms/studio monorepo, workspace imports keep the
source extension: @decocms/ui/components/button.tsx.
Rules
Semantic tokens only, never raw palette.
bg-primary,text-muted-foreground,bg-destructive,border-border— neverbg-red-500ortext-zinc-400.
Available color roles:background,foreground,card,popover,primary,secondary,muted,accent,destructive,success,warning,special
(AI/highlight moments),brand,border,input,ring,sidebar-*
(sidebar surfaces),chart-1..5(data viz). Most roles pair with a*-foregroundtext token.Dark mode is automatic via the
.darkclass on a root element — never
hardcode colors or writedark:overrides that bypass tokens.Compose, don't fork. Extend components with
className+cn(); add
variants through the component'scvaconfig rather than wrapping with
custom styles.font-boldrenders at weight 650 (custom scale); body text is 450.
Radius scale derives from--radius(default 0.375rem).User-facing copy comes from the app, passed as props — components ship
only overridable English defaults.
Component inventory
Forms: button, input, textarea, label, checkbox, radio-group, switch,
slider, select, form (react-hook-form), input-otp, password-input,
datetime-input, email-tags-input, multi-select, search-input, combobox,
time-range-pickerOverlays: dialog, alert-dialog, sheet, drawer, popover, hover-card,
tooltip, command (palette), context-menu, dropdown-menu, menubar,
responsive-dropdown, responsive-select (desktop/mobile adaptive)Feedback: alert, badge, progress, skeleton, spinner, sonner (toasts),
empty-state, empty-state-illustrationsLayout & navigation: card, separator, tabs, accordion, collapsible,
breadcrumb, navigation-menu, pagination, scroll-area, aspect-ratio, table,
sidebar (full app sidebar system), sidebar-footer-shell, app-topbar,
topbar-switcher, user-menu, step-indicatorData & content: avatar, calendar, carousel, chart (recharts + chart tokens),
markdown, entity-card, entity-grid, filter-bar, collection-search,
view-mode-toggle, button-group, toggle, toggle-group
Before using a component, read its source in node_modules/@decocms/ui/src/components/<name>.tsx
(shipped in the package) to see its exact exports and props, or check its page
in the Storybook.
Icons
Components use @untitledui/icons (comes as a dependency). Prefer it in
consuming apps for visual consistency:
import { Plus, SearchMd, Trash01 } from "@untitledui/icons";