W WRNexusJS
Frontend

@wrnexus/ui

Themeable server-rendered UI components and CSS.

bun add @wrnexus/ui@0.2.15
First-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.wrndata-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

NamePurposeKey props
containerMax-width centered content wrapperclass
stackVertical column with gapgap (0–8)
hstackHorizontal row with gapgap (0–8)
gridCSS grid containersee source
dividerHorizontal ruleclass
spacerFlexible/empty spacing elementsee source

Core / feedback

NamePurposeKey props
buttonButtonlabel, variant (default\primary\danger\ghost), size (sm\md\lg), type
inputText inputsee source
textareaMulti-line inputsee source
checkboxCheckboxsee source
badgeSmall status badgelabel, variant
alertCallout boxvariant (info\success\danger\warning), title, message
cardPadded, bordered surfaceclass
avatarUser avatarsee source
spinnerLoading indicatorsee source
disclosureExpandable details/summarysee source
theme-toggleTheme 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.

ExportSignatureReturns
uiComponentsDir() => stringAbsolute path to the .wrn component directory (feed to buildRouter's componentDirs).
uiCssPath() => stringAbsolute path to ui.css.
uiCss() => stringThe 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
  • consumed within the Bun-native WRNexusJS toolchain (Node is not supported).

  • Peer packages: components are discovered and rendered by
  • [@wrnexus/router](../router) (via componentDirs) and served by [@wrnexus/dev-server](../dev-server) / built by [@wrnexus/cli](../cli).

  • Depends on [@wrnexus/core](../core) (dependencies).
  • theme-toggle relies on the framework's theme runtime, which binds the
  • 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/ui

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