# Astro (/docs/astro)
Astro sites get both lanes of the design system, chosen per page — even per
component:
* **Content pages** (Astro's home turf): [`@namche/css`](/docs/html-css) and
ordinary markup in `.astro` components. Zero client JavaScript, which is why
you picked Astro.
* **Interactive islands**: the `@namche` registry via `@astrojs/react` — the
same shadcn components as any product, server-rendered by default and
hydrated only where you add a `client:*` directive.
## Content pages with @namche/css [#content-pages-with-namchecss]
```bash
pnpm add @namche/css
```
```css
/* src/styles/global.css */
@import "@namche/css";
```
Import the stylesheet once (in your base layout or via Astro's global style
handling) and write plain HTML with the [documented classes](/docs/html-css).
Astro's bundler resolves the package imports; nothing else is needed.
## Interactive islands with the registry [#interactive-islands-with-the-registry]
Add React and Tailwind v4 to the site:
```bash
pnpm astro add react
pnpm add tailwindcss @tailwindcss/vite
```
```js
// astro.config.mjs
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
integrations: [react()],
vite: { plugins: [tailwindcss()] },
});
```
Then follow the standard [installation](/docs/installation): `shadcn init -b
base`, register `@namche` in `components.json`, `shadcn add @namche/theme` and
wire the global stylesheet exactly as documented there. Components land in
your own `src/components/ui/` and render inside `.astro` files:
```astro
---
import { Button } from "@/components/ui/button";
import { Dialog, DialogTrigger, DialogContent } from "@/components/ui/dialog";
---
```
A component without a `client:*` directive is rendered to static HTML — free
NAMCHE styling with no hydration cost. Reserve `client:load` /
`client:visible` for components that genuinely need behaviour.
## Fonts [#fonts]
Nothing to do with `@namche/design-tokens` 1.2.0 or later: every face —
Namche Shadow and Geist — loads from `cdn.namche.ai` via the tokens'
`@font-face` rules, and the token stacks already name them. The `geist` npm
package from the [installation page](/docs/installation) is a Next.js
(`next/font`) alternative and does not apply here.
On older token versions Geist is the consumer's job — self-host it:
```bash
pnpm add @fontsource-variable/geist @fontsource-variable/geist-mono
```
```ts
// in your base layout
import "@fontsource-variable/geist";
import "@fontsource-variable/geist-mono";
```
```css
@theme inline {
--font-sans: "Geist Variable", "Geist Sans", ui-sans-serif, system-ui;
--font-display: "Namche Shadow Sans", "Geist Variable", ui-sans-serif;
--font-mono: "Namche Shadow Mono", "Geist Mono Variable", ui-monospace;
}
```
(On a pure CSS-lane site without Tailwind, set the same three variables in a
plain `:root` block instead of `@theme inline`.)
## Dark mode [#dark-mode]
There is no `next-themes` here; the contract is just the `dark` class on
``. A few inline lines in the base layout keep it flash-free:
```html
```
Both lanes follow automatically — every colour is a variable that flips with
the class.
# HTML & CSS (/docs/html-css)
[`@namche/css`](https://www.npmjs.com/package/@namche/css) is the design
system for apps that write plain HTML: Hono services, Astro content pages,
internal tools, anything server-rendered. One stylesheet, no build step, no
framework, no JavaScript — the components on this site restated as CSS
classes.
Both lanes read the same semantic variables from
[`@namche/design-tokens`](https://www.npmjs.com/package/@namche/design-tokens),
so they cannot drift apart: a button is an Erebos pill with an uppercase mono
label whether it came from the registry or from a class attribute.
## Which lane? [#which-lane]
* **React registry** (the rest of these docs) — products and tools that need
interactive components: dialogs, selects, command menus, data tables.
* **`@namche/css`** — server-rendered pages where interactivity is forms and
links. When a page outgrows that, reach for platform elements (`