@wrnexus/ui
Themeable server-rendered UI components and CSS.
bun add @wrnexus/ui@0.2.15First-party Wire UI component library — a set of themeable .wrn components plus a single tokenized stylesheet.
Part of the WRNexusJS framework — an SSR-first, Bun-native full-stack web framework.
Overview
@wrnexus/ui ships a library of server-rendered .wrn components (layout, form controls, and feedback UI) together with one themeable stylesheet, ui.css. The components are auto-discovered by the framework router — you don't import them in code. Once the package's component directory is on the router's scan path, you mount any component in a page with data-component="<name>". Every visual is driven by var(--wire-*) theme tokens, so components restyle instantly when the theme changes. The tiny JS surface (src/index.ts) exists only so the toolchain (CLI build + dev server) can locate the component directory and stylesheet.
Installation
bun add @wrnexus/ui
Private package — the machine must be authenticated to the wrnexus npm org
(a read token in ~/.npmrc). Requires Bun (Node is not supported).
In practice you rarely install this directly: @wrnexus/cli and @wrnexus/dev-server already depend on it and wire it into the router for you (see [Auto-discovery](#auto-discovery)).
Components
Components live as .wrn files under packages/ui/components/. The mount name is the lowercase file basename (e.g. button.wrn → data-component="button"). Each accepts a class prop (appended to its root element) and most render their body from either a named prop or the default slot.
Layout
| Name | Purpose | Key props |
|---|---|---|
container | Max-width centered content wrapper | class |
stack | Vertical column with gap | gap (0–8) |
hstack | Horizontal row with gap | gap (0–8) |
grid | CSS grid container | see source |
divider | Horizontal rule | class |
spacer | Flexible/empty spacing element | see source |
Core / feedback
| Name | Purpose | Key props | |||||
|---|---|---|---|---|---|---|---|
button | Button | label, variant (default\ | primary\ | danger\ | ghost), size (sm\ | md\ | lg), type |
input | Text input | see source | |||||
textarea | Multi-line input | see source | |||||
checkbox | Checkbox | see source | |||||
badge | Small status badge | label, variant | |||||
alert | Callout box | variant (info\ | success\ | danger\ | warning), title, message | ||
card | Padded, bordered surface | class | |||||
avatar | User avatar | see source | |||||
spinner | Loading indicator | see source | |||||
disclosure | Expandable details/summary | see source | |||||
theme-toggle | Theme switch button (binds data-wire-theme-toggle) | label |
Additional controls & data display
Also shipped: select, radio, switch, progress, tag, skeleton, tooltip, and table.
The authoritative, always-current list is uiComponentNames() (below), which reads the component directory at runtime.
API
The JS module (@wrnexus/ui) exposes four helpers used by the build tooling to locate the component assets. There is no component code to import — the components are .wrn files rendered server-side.
| Export | Signature | Returns |
|---|---|---|
uiComponentsDir | () => string | Absolute path to the .wrn component directory (feed to buildRouter's componentDirs). |
uiCssPath | () => string | Absolute path to ui.css. |
uiCss | () => string | The ui.css file contents (all .wire-* classes, themed via tokens). |
uiComponentNames | () => string[] | Sorted list of built-in component names (e.g. for wrnexus eject listing). |
./ui.css asset export
package.json also exposes the raw stylesheet as a subpath asset:
"exports": {
".": "./src/index.ts",
"./ui.css": "./ui.css"
}
The framework serves this stylesheet once at /__wrnexus/ui.css, so pages get all component styles from a single request.
Usage
Auto-discovery
The router scans extra componentDirs (in addition to the app's own app/components) and keys components by name. Library dirs are scanned first and app/components last, so an app component of the same name shadows the library's. The CLI build (@wrnexus/cli) and dev server (@wrnexus/dev-server) both wire the UI directory in for you:
import { buildRouter } from "@wrnexus/router";
import { uiComponentsDir } from "@wrnexus/ui";
const router = buildRouter(appDir, { componentDirs: [uiComponentsDir()] });
Mounting components in a page
Once discovered, mount any component by name via data-component. Quoted attributes (other than data-component) become string props:
<div data-component="card">
<div data-component="badge" label="New"></div>
<button data-component="button" label="Save" variant="primary" size="lg"></button>
<div data-component="alert" variant="success" title="Done" message="Saved."></div>
</div>
Overrides
Ways to customize the components, in increasing order of power:
1. Theme tokens — override CSS custom properties such as --wire-color-primary, --wire-color-surface, --wire-radius-sm, etc. Every component style resolves through var(--wire-*), so changing a token restyles everything instantly (including across theme switches). 2. App CSS — redefine a .wire-* class in your own stylesheet, which is loaded after ui.css and therefore wins. 3. class prop — pass a class prop to a component; it is appended to the component's root element, letting you add per-instance classes without touching the base styles. 4. wrnexus eject <name> — copy the component's .wrn source into your app/components, where (because app components shadow library ones) you fully own and can edit it. Use uiComponentNames() for the list of ejectable names.
Requirements / Notes
- Bun-only — the package uses standard fs/path/url APIs but is published and
- Peer packages: components are discovered and rendered by
- Depends on [
@wrnexus/core](../core) (dependencies). theme-togglerelies on the framework's theme runtime, which binds the
consumed within the Bun-native WRNexusJS toolchain (Node is not supported).
[@wrnexus/router](../router) (via componentDirs) and served by [@wrnexus/dev-server](../dev-server) / built by [@wrnexus/cli](../cli).
data-wire-theme-toggle attribute — no per-component JS is required.
Complete TypeScript API
This declaration is generated from the exact published package and lists its exported functions, classes, interfaces, and types.
/**
* @wrnexus/ui — the Wire UI component library.
*
* Components are `.wrn` files under `components/`, auto-discovered by the
* framework (the router scans this directory in addition to the app's own
* `app/components`). Mount them in any page with `data-component="<name>"`.
* Their styles live in a single themeable stylesheet, `ui.css`, served once at
* `/__wrnexus/ui.css` — every class uses `var(--wire-*)` theme tokens.
*
* Override, in increasing order of power:
* 1. theme tokens (change `--wire-color-primary`, etc.)
* 2. redefine a `.wire-*` class in your own CSS (loaded after ui.css)
* 3. pass a `class` prop (appended to the component root)
* 4. `wrnexus eject <name>` to copy the component into `app/components` and own it
*/
/** Absolute path to the directory of Wire UI component `.wrn` files. */
declare function uiComponentsDir(): string;
/** Absolute path to the Wire UI stylesheet. */
declare function uiCssPath(): string;
/** The Wire UI stylesheet contents (all `.wire-*` classes, themed via tokens). */
declare function uiCss(): string;
/** Names of the built-in components (e.g. for `wrnexus eject` listing). */
declare function uiComponentNames(): string[];
export { uiComponentNames, uiComponentsDir, uiCss, uiCssPath };
Examples
Copy-ready examples taken from this package's published documentation.
Example 1
bun add @wrnexus/uiExample 2
"exports": {
".": "./src/index.ts",
"./ui.css": "./ui.css"
}Example 3
import { buildRouter } from "@wrnexus/router";
import { uiComponentsDir } from "@wrnexus/ui";
const router = buildRouter(appDir, { componentDirs: [uiComponentsDir()] });Example 4
<div data-component="card">
<div data-component="badge" label="New"></div>
<button data-component="button" label="Save" variant="primary" size="lg"></button>
<div data-component="alert" variant="success" title="Done" message="Saved."></div>
</div>