# Using shadcn/ui [shadcn/ui](https://ui.shadcn.com) copies React components into your own source tree, built on Radix primitives and Tailwind. A site created with `aircloud new` is ready for it: the React template uses Tailwind by default, and `@/` already resolves to `src/` in both `vite.config.js` and `jsconfig.json`. This guide takes a site from `shadcn init` to a release that verifies clean, under the product's default Content-Security-Policy. ## Set it up inside the site Run the shadcn CLI in the site directory, `app/site/`, never at the product root: ```sh cd app/site npx shadcn@latest init ``` `init` writes `app/site/components.json`, next to `package.json`. The site admits any top-level `.json` file there as a tooling manifest that the build never reads, so `components.json` needs no exception. Two names are refused: `tsconfig.json` (the site is JavaScript, and `jsconfig.json` already declares its paths) and any `.json` file whose name starts with a dot. Make sure `components.json` carries these values: ```json { "tsx": false, "rsc": false, "tailwind": { "css": "src/styles/application.css" }, "aliases": { "components": "@/components", "ui": "@/components/ui", "utils": "@/lib/utils", "lib": "@/lib", "hooks": "@/hooks" } } ``` - **`tsx: false`.** The site is JavaScript. With `tsx` false, shadcn writes `.jsx` and `.js` files instead of `.tsx` and `.ts`, and resolves the `@/` aliases through `jsconfig.json`. - **`rsc: false`.** A Vite site has no React Server Components. - **`tailwind.css`** is the generated stylesheet, under `app/site/src/styles/`. Every `.css` file in that directory, at any depth, is admitted. - **The aliases.** `@/` is `src/`, so components land under `app/site/src/components/ui/`. Nested directories under `app/site/src/components/` are admitted. The `cn` helper lands in `src/lib/utils.js`: `src/` is open to your own directories, except for its fixed entries (`main.jsx`, `application.jsx`, `routes.js`, `layouts/`, `components/`, `helpers/`, `pages/` and `styles/`). Add components the same way, from `app/site/`: ```sh npx shadcn@latest add dialog aircloud check ``` A component's unit test mirrors its path. For `app/site/src/components/ui/dialog.jsx`, the test goes under `test/site/components/`, in the same `ui/` subdirectory, as `dialog.test.jsx`. ## Remove the CLI once you have scaffolded `shadcn init` can leave the `shadcn` package in the site's dependencies: your stylesheet imports `shadcn/tailwind.css` from it. The running site doesn't need a scaffolding tool. Once the components you need are in place, eject it: ```sh npx shadcn@latest eject ``` `eject` copies the content of `shadcn/tailwind.css` into your stylesheet in place of the import. It then removes `shadcn` from `package.json` with your package manager (`npm uninstall shadcn` for an npm site), which also rewrites `package-lock.json`. On the site this guide was written against, the lockfile went from 460 packages to 168. `eject` asks for confirmation (`--yes` skips it) and cannot be undone: later shadcn updates to that stylesheet no longer apply automatically. If your stylesheet doesn't import `shadcn/tailwind.css`, `eject` reports "Nothing to eject" and changes nothing. In that case, if `shadcn` is still in `package.json`, run `npm uninstall shadcn` yourself. You can keep adding components after ejecting. `npx shadcn@latest add` runs the CLI without making it a dependency. ## The content policy needs no edit A product site runs under the policy in `config/content_security_policy.toml`. Its default `style_src` is `'self'`, which admits no inline style. Radix and sonner create `