The item contract

tradecn items compose the consumer's @/components/ui/* exports so shadcn can change its styles or base without changes to tradecn's files. These rules define that boundary. scripts/validate-registry.ts and ESLint check the source; the browser matrix checks the installed components in radix-nova, base-mira, and base-vega.

Updating

Use --diff to review an update. Replace <item> with the item name and the example tag with the version you want:

pnpm dlx shadcn add "tradecn/ui/<item>#v0.2.0" --diff
pnpm dlx shadcn add table --diff
npx shadcn add "tradecn/ui/<item>#v0.2.0" --diff
npx shadcn add table --diff
yarn dlx shadcn add "tradecn/ui/<item>#v0.2.0" --diff
yarn dlx shadcn add table --diff
bunx --bun shadcn add "tradecn/ui/<item>#v0.2.0" --diff
bunx --bun shadcn add table --diff

The first reviews a tradecn item; the second reviews a shadcn built-in. tradecn bundles its own files and names shadcn built-ins as dependencies.

A bare --diff lists file changes but omits CSS changes, so a theme with no files shows no diff. Review stylesheet changes separately by running the command again with the tailwind.css path from your components.json, such as --diff src/index.css. This shows only the stylesheet diff. After reviewing both, remove --diff and its path to apply the update.

Files and imports

  1. Item types follow their location. registry:component is not an item type.

    Location under registry/tradecn/ Item type
    ui/* registry:ui
    hooks/* registry:hook
    lib/* registry:lib
    blocks/* registry:block
    No files registry:theme, for opt-in themes only

    Block files may use registry:block, registry:page, registry:component, or registry:file. The registry:page and registry:file types require explicit targets.

    Files under agents/ are Markdown for a coding agent, bundled by the item that installs them as registry:file with an explicit target. They are not source: the source rules below and just tokens read .ts and .tsx files only.

  2. Bundle shared tradecn code in files[], with a type per file. Never put another tradecn item in registryDependencies: the GitHub install form does not pass #ref to dependencies, so an item pinned to v0.1.0 could pull siblings from main. Shared files across items stay byte-identical and merge cleanly.

  3. registryDependencies are bare shadcn built-in names. Each must be in registry/tradecn/builtins.lock.json, with every imported symbol exported in all three locked styles. just lock-builtins-check refetches upstream; the nightly job runs that check.

  4. Use the supported import paths. Own-file imports must resolve to files in the item's files[].

    Source Import form
    tradecn files @/registry/tradecn/{ui,hooks,lib}/x
    shadcn built-ins @/components/ui/x
    Class helper import { cn } from "cn"
    npm packages Declared in dependencies and registry/tradecn/deps.allow.json
    React peers react and react-dom, without a dependency entry

    Relative imports, @/lib/utils, and other registry aliases are forbidden. So are direct imports of radix-ui, @radix-ui/*, @base-ui/*, @base-ui-components/*, cmdk, and react-resizable-panels.

  5. Do not use asChild, render, or nativeButton in registry JSX. Style a shadcn trigger with className or pass children. Use className="contents" when it must wrap a tradecn element.

  6. Declare dependencies as name@^x.y.z, using the allowlist's exact range. Every declared dependency must be imported. Items do not use devDependencies.

Tokens and CSS

  1. Generate cssVars with just tokens. It reads registry/tradecn/tokens.json and includes the tokens an item's files use, their referenced tokens, and the accessible font pair when needed. For example, using --tradecn-font-numeric also installs --tradecn-font-sans because its value is var(--tradecn-font-sans).

    Token Value
    Colors Literal oklch(...) or var(--color-<shadcn token>); the CLI creates Tailwind color utilities
    tradecn-font-* Font stacks; tradecn-font-weight-* holds weights
    tradecn-text-size-* px sizes
    tradecn-line-height-* Unitless line heights
    tradecn-numeric-variant lining-nums tabular-nums

    Typography tokens are written as-is into :root and .dark, without color aliases. Installing a UI item on its own preserves existing variables such as --up, --down, and --tradecn-font-sans. A theme enables variable overwrites for the whole install.

  2. Limit non-theme css to keyframes, third-party restyles, and the accessibility remap. Style elements, shadcn classes, and tradecn slots in source files.

    Allowed CSS Requirement
    @keyframes tradecn-* Prefix animation names with tradecn-
    @layer components Selectors start with .dockview-theme-tradecn or .dv-*; set the package's custom properties because its unlayered rules beat layered restyles
    Accessibility remap Generated by just tokens for items that read a font token

    Workspace's floating-container rule uses !important to replace Dockview's unlayered self-reference with inheritance. Set overlay z-index overrides on the theme root.

    The remap uses :root[data-accessibility="hyperlegible"], [data-accessibility="hyperlegible"] to point --tradecn-font-sans and --tradecn-font-mono at the accessible pair. It works without a theme and stays unlayered so it can override the unlayered :root tokens on <html>.

Metadata and composition

  1. Require title, description, and categories. Also require docs when an item has css, cssVars, or a dependency beyond cn. meta.components must name exports from the primary file.
  2. Name the item after its primary file's basename. A registry:ui or registry:block root carries data-slot="tradecn-<name>".
  3. Supply any provider a built-in needs in either base. An item using tooltips wraps itself in <TooltipProvider> without configuration props, because the prop names differ by base. Radix requires the provider; Base UI does not. Export checks cannot catch this runtime difference, so components have smoke scenes in all three consumers.
  4. Keep file basenames unique within an item, regardless of directory or extension. CLI 4.21.0 resolves own-file imports by basename, preferring .tsx over .ts before matching the requested path. Pairing lib/sparkline.ts with ui/sparkline.tsx can make the installed component import itself, even though source and built JSON resolve correctly. The validator rejects this; the library is named sparkline-geometry.ts.

Themes

  1. A theme replaces the consumer's variables; its docs must say so first. Among tradecn item types, only registry:theme does this. It has no files and sets every tradecn token in both cssVars.light and cssVars.dark, so none retain values from the previous palette.

    Token values follow rule 7. A theme's css must exactly match THEME_TYPOGRAPHY_CSS in scripts/lib/registry.ts: the numeric variant on :root and .tradecn-num, [data-numeric] in @layer base, plus the accessibility remap. Other items cannot carry that base layer.

    just tokens leaves themes alone: deriving tokens from an empty file list would erase them. The validator rejects empty themes and missing tokens.

Typography

  1. Any component rendering numeric data MUST set font-variant-numeric: lining-nums tabular-nums on the numeric node.

    Use NUMERIC_CLASS, MONO_NUMERIC_CLASS, or numericFontClass(convention) from format. tabular-nums alone replaces the whole property and drops lining figures; the validator rejects it without lining-nums on the same source line.

    Read fonts through tokens, for example font-(family-name:--tradecn-font-mono). Tailwind's font-mono, font-sans, and font-serif bypass the consumer's --tradecn-font-* choices and are forbidden. Keep text at least 12 px, the floor named by --tradecn-text-size-grid-min. The validator rejects smaller arbitrary classes (text-[10px], text-[0.6rem]) and smaller fontSize values, in a style or as an attribute; text-xs is the smallest named size to use. SVG text takes its size in the viewBox's units, so a chart drawn at its own size labels at fontSize={12} or more.

    A compact style draws some built-ins under the floor. base-mira draws Badge, Kbd, CommandShortcut, ContextMenuShortcut, DropdownMenuShortcut, Button size="xs", and NativeSelect size="sm" at 10 px, so set text-xs or larger on each one an item composes. A small select takes it as [&_select[data-size=sm]]:text-xs, because base-mira's rule sits on the select itself and outranks a plain [&_select]:text-xs on the wrapper. A key inside an InputGroupAddon takes it on the addon as [&_kbd[data-slot=kbd]]:text-xs, because the addon's own rule for its keys outranks the key's class. scripts/typography.test.ts holds the registry, the demos, and the scenes to this.

    The browser matrix checks computed numeric styles in all three consumers, with and without each theme. It checks elements whose own text contains a digit and inputs containing digits under tradecn slots, plus every [data-numeric] node. The site smoke checks every preview the same way. typography.md explains the choices.

Direction

  1. Carry direction in more than hue. A value using text-up, bg-down-soft, stroke-up, or another direction color also needs a sign from formatSigned, a data-direction attribute, screen-reader text, or a visible label such as Buy. Red and green are not distinguishable to every reader, and their meanings reverse in some markets.

    Add each file that uses direction colors to the channel table in scripts/color.test.ts, with evidence of its other channel. The test fails on an unlisted file. Every theme's up/down pair and the items' default pair must also have a grayscale contrast ratio of at least 1.3:1 in both modes.

What a version means

The tag is the version. From v0.1.3 on, tradecn follows semver with no pre-1.0 exceptions.

Release Meaning
Major (v1.0.0, v2.0.0) An installed file's API changes: a prop, export, hotkey, token name, or data-slot. Read ⚠ Breaking Changes in the release notes and use --diff before updating.
Minor New items or backward-compatible props. Existing usage keeps working.
Patch Files change without API changes: fixes, performance work, refactors, or cleanup. --diff shows the changes.

A patch can contain only docs: tradecn.dev serves the docs from its release tag, so documentation changes need a release to appear. Such a tag has no installed-file diff. CI and test changes do not release. CONTRIBUTING.md explains how PR titles pick the bump.

This page is docs/contract.md at v2.0.0.