NAMCHE UI

HTML & CSS

The zero-build lane — NAMCHE for server-rendered HTML, no React required.

@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, 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?

  • 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 (<dialog>, popover, <details>) styled by the same tokens before reaching for React.

The React components are canonical. If the CSS lane renders something differently, that is a bug in @namche/css.

Install

npm install @namche/css

With a bundler (Vite, Astro, …) one import brings tokens, theme and components:

@import "@namche/css";

Without a build step, inline the files into your page <style> (or serve them statically) in the order styles.css declares: the tokens, the semantic bridge, then the components. Apps that already load the tokens import @namche/css/components.css alone. In a Hono app, resolve the files from node_modules at startup and cache the concatenated result.

Use

<button class="btn">Save</button>
<a class="btn btn-outline btn-sm" href="/edit">Edit</a>

<div class="card">
  <div class="card-header">
    <div class="card-title">Expedition</div>
    <div class="card-description">Eight members, two routes.</div>
  </div>
  <div class="card-content prose"><p>…</p></div>
  <div class="card-footer"><button class="btn btn-sm">Review</button></div>
</div>

<div class="field">
  <label class="label" for="name">Name</label>
  <input class="input" id="name" placeholder="Ang Tharkay" />
  <span class="field-description">As recorded in the permit.</span>
</div>

The vocabulary:

ClassesMirrors
.btn + -outline -secondary -ghost -destructive -link, sizes -xs -sm -lg -iconButton
.badge + -secondary -outline -destructiveBadge
.card, .card-header -title -description -action -content -footer, .card-smCard
.input .textarea .select .label .field .field-descriptionInput, Textarea, Label
.table (wrap in .table-container for overflow)Table
.alert, .alert-title -description, .alert-destructiveAlert
.separator, .separator-verticalSeparator
.kbdKbd
.proserunning text with the editorial link voice

States follow the platform: disabled, :focus-visible and aria-invalid="true" render the same treatments as the React lane.

Dark mode

Same contract as the registry: add the dark class to <html>. Every colour is a variable that flips with the class — no second stylesheet.

Fonts

Nothing to do: every face loads from cdn.namche.ai via the tokens' @font-face rules — Namche Shadow always, and Geist since @namche/design-tokens 1.2.0. On older token versions Geist is the consumer's job (self-host it, for example via @fontsource-variable/geist); without it the token stacks fall back to system fonts.

On this page