# Introduction Build, document, and deploy this custom shadcn registry. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). This repository publishes a custom [shadcn registry](https://ui.shadcn.com/docs/registry) with a documentation site, live component previews, generated registry JSON, and machine-readable docs for AI coding assistants. The app is a static-hostable TanStack Start SPA deployed to Cloudflare Workers with Worker Static Assets. Component docs are authored in MDX with Fumadocs, registry items are built from `registry.json`, and generated files are served from stable public URLs. ## What this repo includes - **Fumadocs documentation** in `content/docs`, discovered from the filesystem. - **shadcn registry output** generated from `registry.json` into `public/r`. - **Live component previews** that can render examples from `examples` or inline MDX. - **A default `luma` registry style** for new components, plus the current placeholder item. - **Static AI documentation endpoints** such as `/llms.txt`, `/llms-full.txt`, and `/llms.md/...`. - **Cloudflare Workers deployment** using Worker Static Assets. ## Tech Stack - `TanStack Start` - `TanStack Router` - `React 19` + `TypeScript` - `Vite` - `Tailwind CSS 4` - `Fumadocs` - `shadcn/ui` - `motion` - `shiki` + `rehype-pretty-code` - `Cloudflare Workers` ## How It Works 1. Add or edit registry source in `src/registry/luma`. 2. Add the registry item to `registry.json`. 3. Document the component in `content/docs/components`. 4. Render a preview with `ComponentPreview`. 5. Build the generated registry files with `pnpm registry:build`. 6. Build generated docs and agent files with `pnpm static:build`. Once deployed, users can install registry items with the shadcn CLI: ```bash npx shadcn@latest add https://tanstartercn.tsu.moe/r/button.json ``` ## Important Paths - `content/docs` - MDX documentation pages. - `examples` - reusable preview examples. - `src/registry/luma` - installable registry component source. - `src/shared/components` - app and docs UI. - `src/shared/components/ui` - complete shadcn/ui primitives used by the site. - `src/shared/lib/registry.ts` - preview/component lookup wiring. - `registry.json` - shadcn registry manifest. - `public/r` - generated registry JSON files. - `scripts/generate-static-assets.mjs` - generated docs, LLM, sitemap, and discovery files. Do not edit generated output by hand. Regenerate it with the matching script instead. ## Public Endpoints - `/r/registry.json` - registry index. - `/r/button.json` - individual registry item. - `/llms.txt` - quick AI docs index. - `/llms-full.txt` - complete generated docs. - `/openapi.json` - machine-readable endpoint catalog. - `/.well-known/agent-skills/index.json` - agent skill discovery. The production origin comes from `FALLBACK_SITE_ORIGIN` in `src/shared/constants/site.ts`, unless `SITE_URL` is provided at build time. ## Common Commands ```bash pnpm dev pnpm registry:build pnpm static:build pnpm typecheck pnpm check pnpm build pnpm deploy ``` Use `pnpm registry:build` after registry changes, `pnpm static:build` after docs or static endpoint changes, and `pnpm build` before deploy. ## Next Steps Read [Installation](/docs/installation) to install registry components, [Styling](/docs/styling) to customize tokens, [Components](/docs/components) to browse registry items, and [Extending](/docs/extending) to add new docs pages or components. # Components Browse the components available in this registry. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). # Button Displays a button or a component that looks like a button. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). ## Installation ```bash npx shadcn@latest add https://tanstartercn.tsu.moe/r/button.json ``` ```bash npm install radix-ui ``` ## Usage ```tsx import { Button } from "@/components/ui/button"; ``` ```tsx ``` ## Examples ### Start aligned ### Hidden code ### Inline example ```tsx import { Button } from "@/components/ui/button"; export function InlineButtonExample() { return ; } ``` # Your Component Basic usage of the YourComponent template. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). ## Usage After you add the component with the CLI, import it from your UI folder: ```tsx import { YourComponent } from "@/components/ui/your-component"; export function MyComponent() { return ; } ``` # Extending How to add docs pages, registry components, previews, and clear examples. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). This project has two extension paths: documentation pages in `content/docs` and installable shadcn registry items in `src/registry`. Most changes should keep those paths connected so readers can see the component, copy the usage, and install the same source from `/r/.json`. ## Add a docs page Create MDX under `content/docs`. Put general guides in `content/docs/(root)` and component reference pages in `content/docs/components`. ```txt content/docs/(root)/my-guide.mdx content/docs/components/my-component.mdx ``` Every page should start with frontmatter: ```mdx --- title: My Guide description: A direct sentence that explains what the page helps with. --- ``` Pages are discovered automatically from the filesystem. The file name creates the route, and the frontmatter creates the label. ```txt content/docs/(root)/extending.mdx -> /docs/extending content/docs/components/button.mdx -> /docs/components/button ``` Use `meta.json` only as an optional override for folder metadata or custom ordering. If a folder has no `meta.json`, the docs tree still includes every MDX file in that folder. Use short headings, small examples, and task-focused sections. A good page answers what to edit, where to put it, how to wire it, and how to verify it. ## Add a registry component Put installable source under the style folder. The default style is `luma`. ```txt src/registry/luma/my-component.tsx ``` Use shadcn-compatible imports in registry source. The installed code should import from paths that exist in a user's app, such as `@/lib/utils` and `@/components/ui/button`. If you need an upstream shadcn/ui primitive first, add it with: ```bash pnpm exec shadcn add ``` Add the component to `registry.json`: ```json { "name": "my-component", "type": "registry:ui", "title": "My Component", "description": "A concise description of what it provides.", "dependencies": ["radix-ui"], "files": [ { "path": "src/registry/luma/my-component.tsx", "type": "registry:ui", "target": "components/ui/my-component.tsx" } ] } ``` Use `dependencies` for npm packages the installed component needs. Use the file `target` for the path users should receive in their app. Then wire the preview in `src/shared/lib/registry.ts`: ```tsx import { MyComponent } from "@/registry/luma/my-component"; const registryComponents: RegistryComponentMap = { luma: { "my-component": MyComponent as RegistryComponent, }, }; ``` Do not edit `public/r/*` by hand. Run `pnpm registry:build` after registry changes. ## Add a block to `/blocks` Blocks are larger installable examples, such as full pages, dashboard shells, auth screens, or composed sections. They appear in the `/blocks` browser when an item in `registry.json` uses `type: "registry:block"`. Put block source under a named folder in the registry style: ```txt src/registry/luma/my-block/page.tsx src/registry/luma/my-block/components/my-block-sidebar.tsx ``` Use install-friendly imports inside block source, just like registry components. For example, a block should import primitives from `@/components/ui/button`, not from this site's `src/shared` paths. If the block needs upstream shadcn/ui primitives, add them first: ```bash pnpm exec shadcn add ``` Then add the block to `registry.json`: ```json { "name": "my-block", "type": "registry:block", "title": "My Block", "description": "A concise description of the composed UI.", "registryDependencies": ["button", "card"], "categories": ["dashboard"], "files": [ { "path": "src/registry/luma/my-block/page.tsx", "type": "registry:page", "target": "app/dashboard/page.tsx" }, { "path": "src/registry/luma/my-block/components/my-block-sidebar.tsx", "type": "registry:component", "target": "components/my-block-sidebar.tsx" } ] } ``` Use `registryDependencies` for shadcn registry items the block needs, such as `button`, `card`, `sidebar`, or `breadcrumb`. Use `dependencies` for npm packages. Wire the live preview in `src/shared/lib/registry.ts`: ```tsx import MyBlockPage from "@/registry/luma/my-block/page"; const registryComponents: RegistryComponentMap = { luma: { "my-block": MyBlockPage as RegistryComponent, }, }; ``` The `/blocks//preview` route renders that registered component in an iframe. The `/blocks` page reads its catalog from `registry.json`; `/blocks?category=` opens the searchable category view, so you do not add a separate list item by hand. ## Configure block categories Block categories come from each block item's `categories` array in `registry.json`. ```json "categories": ["sidebar", "dashboard"] ``` The category catalog is derived in `src/shared/lib/blocks.ts`. That file groups `registry:block` items, creates counts, and adds the special `all` category. If a category needs a custom display name, add it to `categoryTitles`: ```ts const categoryTitles: Record = { sidebar: "Sidebar", }; ``` If there is no custom title, the site title-cases the category name automatically. For example, `emptyState` becomes `Empty State`, and `order-confirmation` becomes `Order Confirmation`. ## Customize block category preview art The preview art on `/blocks` lives in `src/shared/components/blocks/block-category-grid.tsx`. Each category can map to a small skeleton preview: ```tsx const CATEGORY_SKELETONS: Record = { sidebar: SidebarSkeleton, login: AuthSkeleton, }; ``` Add a new skeleton component in that file when a category needs a distinct visual. Keep these previews decorative and generic: use muted skeleton shapes, small card layouts, and theme tokens rather than real app content or hard-coded brand colors. If a category is not mapped, it uses `DefaultSkeleton`. ## How the block browser is wired The block browser is split across a few files: - `src/routes/blocks.tsx` owns the blocks layout route and shared metadata. - `src/routes/blocks.index.tsx` renders the category grid when no category is selected and the searchable block list when `category` is present in the URL. - `src/routes/blocks.$block.preview.tsx` renders the iframe-only preview target. - `src/shared/components/blocks/block-preview-list.tsx` owns category filtering, search, empty state, and bottom navigation. - `src/shared/components/blocks/block-showcase.tsx` owns the preview/code tabs, responsive preview controls, reload button, fullscreen link, and copy command. - `src/shared/components/blocks/block-code-explorer.tsx` reads the files listed in `registry.json` and shows the code browser. Most new blocks only require three edits: add files under `src/registry/luma`, add the block item to `registry.json`, and register the preview in `src/shared/lib/registry.ts`. Add category titles or category art only when the defaults are not enough. ## Write component docs Component docs should show the preview first, then installation, usage, and meaningful variants. ````mdx --- title: My Component description: A concise description of what the component does. --- ## Installation ```bash npx shadcn@latest add https://your-site.com/r/my-component.json ``` ## Usage ```tsx import { MyComponent } from "@/components/ui/my-component"; ``` ```tsx ``` ## Examples ```` Pages are discovered automatically from the filesystem. Prefer real use cases over prop inventories. Good examples are named after the situation they demonstrate, such as "With icon", "Loading", "Form field", or "Empty state". ## Preview from an examples file Use an `examples` file when the same demo is reused or when the example is large enough to deserve its own module. ```txt examples/my-component-demo.tsx ``` ```tsx import { MyComponent } from "@/registry/luma/my-component"; export default function MyComponentDemo() { return Save changes; } ``` Then reference it from MDX: ```mdx ``` The examples directory is loaded dynamically, so keep file names stable and use kebab-case names that match the preview name. If the demo is reused by multiple pages, import it in `src/shared/lib/registry.ts` and add it to `demoComponents`. ## Preview inline Use inline previews when the example only belongs to one docs page. ````mdx import { Button } from "@/registry/luma/button"; ```tsx import { Button } from "@/components/ui/button"; export function InlineButtonExample() { return ; } ``` ```` The JSX child renders the live preview. The fenced `tsx` block becomes the source panel users copy from. ## Show source directly Use `ComponentSource` when the page needs to show the registry file itself. ```mdx ``` Use a `title` that matches the installed target path when possible. ## Smoke-test registry output For a public registry, smoke-test generated files with the shadcn CLI: ```bash npx shadcn@latest add https://your-site.com/r/my-component.json --dry-run ``` Before deploy, confirm `/r/registry.json`, `/r/my-component.json`, the docs page, and `/llms-full.txt` resolve from the built app. ## Documentation checklist Before finishing, check that the page has: - A specific title and description. - A working primary preview near the top. - Installation and usage snippets that match the registry target. - Examples that teach real decisions, not every possible prop. - Links or notes for dependencies when the user must install something extra. - A verification section only when it helps the reader complete the task. ## Verification Run the checks that match the change: ```bash pnpm registry:build pnpm static:build pnpm typecheck pnpm check pnpm build ``` Use `pnpm registry:build` for registry changes and `pnpm static:build` for docs changes. `pnpm build` runs both and verifies the deployable app. # Installation Install registry components in your project. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). ## Prerequisites Components are distributed through the [shadcn registry](https://ui.shadcn.com/docs/registry) format. Before installing a component, make sure your project has: - React - Tailwind CSS v4 - shadcn/ui initialized - a `components` alias that resolves to your app's component directory For a new project, initialize shadcn first: ```bash npx shadcn@latest init ``` ## Adding components ### CLI Install the Button component from this registry: ```bash npx shadcn@latest add https://tanstartercn.tsu.moe/r/button.json ``` The CLI copies the component source into your project and installs the npm dependencies declared by the registry item. Then import it from the target path: ```tsx import { Button } from "@/components/ui/button"; export function Example() { return ; } ``` ### Manual Copy component source from the component docs via the Manual tab. Manual installation is useful when you want to review the source before adding it to your project. ### Registry index The registry index is available at: ```bash https://tanstartercn.tsu.moe/r/registry.json ``` Use the index to inspect available components. Install individual components with their `/r/.json` URL. # LLMS.txt Let AI coding assistants use tanstartercn documentation and registry references. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). tanstartercn provides [llms.txt](https://llmstxt.org/) endpoints so AI coding assistants can fetch documentation, registry links, and page-specific markdown directly by URL. ## Available files **Core documentation:** - [/llms.txt](/llms.txt) - Quick reference index for documentation and agent resources. - [/llms-full.txt](/llms-full.txt) - Complete generated documentation in one file. **For limited context windows:** - [/llms.md/content.md](/llms.md/content.md) - Homepage markdown. - [/llms.md/docs/content.md](/llms.md/docs/content.md) - Docs index markdown. - [/llms.md/docs/components/button/content.md](/llms.md/docs/components/button/content.md) - Single-page component documentation. **Agent discovery:** - [/.well-known/agent-skills/index.json](/.well-known/agent-skills/index.json) - Agent skill discovery index. - [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md) - Site skill instructions for agents. - [/openapi.json](/openapi.json) - Machine-readable endpoint catalog. ## Integration **Claude Code:** Reference the docs in your prompt or project instructions: ```bash Use tanstartercn documentation from https://tanstartercn.tsu.moe/llms.txt ``` **Cursor:** Use the `@Docs` feature: ```bash @Docs https://tanstartercn.tsu.moe/llms-full.txt ``` [Learn more](https://docs.cursor.com/context/@-symbols/@-docs) **Windsurf:** Add the docs URL to your rules: ```bash #docs https://tanstartercn.tsu.moe/llms-full.txt ``` [Learn more](https://docs.codeium.com/windsurf/memories#memories-and-rules) **Other AI tools:** Most assistants accept documentation URLs: ```bash https://tanstartercn.tsu.moe/llms.txt ``` For complete documentation: ```bash https://tanstartercn.tsu.moe/llms-full.txt ``` For a specific docs page: ```bash https://tanstartercn.tsu.moe/llms.md/docs/components/button/content.md ``` ## Contributing If AI-generated code misses a registry path, install command, or component example, update the source docs in `content/docs` and regenerate static assets with `pnpm static:build`. # Styling Style registry components with Tailwind CSS v4 and shadcn tokens. > For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available at explicit `.md` URLs. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md). ## Overview Registry components are styled with Tailwind CSS v4 utility classes and shadcn-compatible CSS variables. The installed source expects your app to provide the standard theme tokens such as `background`, `foreground`, `primary`, `border`, `input`, `ring`, and `radius`. The default registry style is `luma`. It keeps component source portable by using semantic utilities like `bg-primary`, `text-primary-foreground`, `border-input`, and radius tokens instead of hard-coded one-off colors. ## Prerequisites Before adding components, make sure your project has Tailwind CSS v4 and shadcn/ui initialized: ```bash npx shadcn@latest init ``` See [Installation](/docs/installation) for the registry install commands. ## Theme tokens Tailwind v4 reads this project's shadcn tokens through `@theme inline`. If your app was initialized with shadcn/ui, you already have the same basic structure. ```css title="globals.css" @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); } ``` ## Color convention Each surface token has a matching foreground token. The base token is the fill color. The `-foreground` token is the text and icon color that should sit on that fill. ```tsx
``` Use token pairs together when you create new component states: - `bg-background text-foreground` - `bg-card text-card-foreground` - `bg-popover text-popover-foreground` - `bg-primary text-primary-foreground` - `bg-secondary text-secondary-foreground` - `bg-muted text-muted-foreground` - `bg-accent text-accent-foreground` ## Customizing colors Override CSS variables on `:root` and `.dark`. Always update the foreground token when you change a fill token. ```css title="globals.css" :root { --primary: oklch(0.62 0.18 250); --primary-foreground: oklch(0.99 0 0); --ring: oklch(0.62 0.18 250); } .dark { --primary: oklch(0.72 0.16 250); --primary-foreground: oklch(0.16 0.02 250); --ring: oklch(0.72 0.16 250); } ``` ## Adding tokens New variables need two pieces: a CSS variable and a Tailwind `--color-*` mapping inside `@theme inline`. ```css title="globals.css" @theme inline { --color-brand: var(--brand); --color-brand-foreground: var(--brand-foreground); } :root { --brand: oklch(0.62 0.18 250); --brand-foreground: oklch(0.99 0 0); } .dark { --brand: oklch(0.72 0.16 250); --brand-foreground: oklch(0.16 0.02 250); } ``` Then use the token like any other Tailwind color: ```tsx
``` ## Radius scale The base `--radius` token controls the component radius scale. ```css title="globals.css" @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); } :root { --radius: 0.625rem; } ``` Button uses this scale for size-specific corners, so changing `--radius` updates the shape of installed components without editing component source. ## Registry component notes Installed components are meant to live in your app. After installation, you can edit the copied source directly. Keep these rules in mind when changing styles: - Prefer semantic tokens over literal colors. - Keep hover, focus, disabled, and dark-mode states readable. - Use `ring` and `ring-offset` tokens for focus states.