Contributing
How to work inside the nx-ui repo itself — the source of the registry, the showcase and the agent skills. AGENTS.md is the single source of truth; this is the orientation.
The verify loop
One command is the whole gate — typecheck, then registry build, then the app build. CI runs exactly this:
shell
bun run checkbun run check=tsc --noEmit+registry:build+next build. A staleregistry.jsonorpublic/r/fails the build rather than silently drifting.bun run smoke— the interaction smoke test: headless Chromium clicks every button on every showcase page (needsbun run devrunning). It catches popup-mount errors that builds cannot — e.g. a Base UI menu label placed outside a Group. Run it after touching menus, dialogs or blocks.bun run registry:build— regeneratespublic/r/*.jsonfromregistry.json. Run it after touchingcomponents/, and commit the regenerated output — consumers install from those files.
Rebuild the registry after touching components
After changing any file under
components/ or registry.json, run bun run registry:build and commit the regenerated public/r/ output. That committed JSON is the artefact raw.githubusercontent.com actually serves — git push is the deploy.The minimal-diff doctrine
Components stay as close to the upstream shadcn base-vega sources as possible — upstream diffability is a feature. Restyling happens through the theme first, class deltas second. The permitted deltas:
- Tokens do most of the work — the layer-2 mapping restyles components for free.
- Shadows, focus ring, type, radii follow the UUI system (controls get
shadow-xs; a 4px brand-tinted focus ring; control labelsfont-semibold; controlsrounded-lg, cardsrounded-xl, pillsrounded-full). - Icons swap
lucide-react→@untitledui/iconsequivalents. - Never changea component's exports, props, Base UI part structure, data-attributes or file/export names — a consumer following shadcn docs must not be surprised.
The full record of the design decisions lives in
docs/architecture.md. Read it before changing components, tokens or registry structure. Conventions: kebab-case files, British English, one component per file, no barrel-file re-export mazes.How demos, pages and nav are generated
bun run registry:build chains three steps, so a new component or page self-registers:
shell
bun run registry:build # build-registry.ts → shadcn build → nav:buildscripts/build-registry.tsscans the repo and generatesregistry.json— one item per file incomponents/ui/,components/ai/andcomponents/blocks/, plus hooks, lib modules, datasets and the theme items. Per-item dependencies are derived by parsing each file's own imports, so the registry never drifts out of sync with the source.bunx shadcn buildreads thatregistry.json, inlines each file's contents, and writes one flattened JSON per item intopublic/r/.scripts/build-nav.ts(nav:build) scans the route sections underapp/(showcase)/and regenerates the nav manifest. Every section directory with per-itempage.tsxsubdirectories becomes a nav section; titles and descriptions resolve fromregistry.json, then an optional section_meta.json, then a Title-Cased slug.
To add a component: drop the file in
components/ui/, add a demo page under app/(showcase)/components/<name>/page.tsx, run bun run check, and commit the regenerated public/r/ and nav manifest. No nav wiring by hand.Back to the documentation index, or read Getting started to see the consumer side of the same registry.