NAMCHE UI

Astro

NAMCHE in an Astro site — CSS lane for content, React islands where needed.

Astro sites get both lanes of the design system, chosen per page — even per component:

  • Content pages (Astro's home turf): @namche/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

pnpm add @namche/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. Astro's bundler resolves the package imports; nothing else is needed.

Interactive islands with the registry

Add React and Tailwind v4 to the site:

pnpm astro add react
pnpm add tailwindcss @tailwindcss/vite
// 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: 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:

---
import { Button } from "@/components/ui/button";
import { Dialog, DialogTrigger, DialogContent } from "@/components/ui/dialog";
---

<Button>Static — rendered to HTML, no JS shipped</Button>
<Dialog client:load>…</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

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 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:

pnpm add @fontsource-variable/geist @fontsource-variable/geist-mono
// in your base layout
import "@fontsource-variable/geist";
import "@fontsource-variable/geist-mono";
@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

There is no next-themes here; the contract is just the dark class on <html>. A few inline lines in the base layout keep it flash-free:

<script is:inline>
  const stored = localStorage.getItem("theme");
  const dark = stored ? stored === "dark"
    : matchMedia("(prefers-color-scheme: dark)").matches;
  document.documentElement.classList.toggle("dark", dark);
</script>

Both lanes follow automatically — every colour is a variable that flips with the class.

On this page