@wrnexus/ui
First-party Wire UI component library — a set of themeable
.wrncomponents plus a single tokenized stylesheet.
Part of the WrNexus 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
wrnexusnpm 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).
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:
- Theme tokens — override CSS custom properties such as
--wire-color-primary,--wire-color-surface,--wire-radius-sm, etc. Every component style resolves throughvar(--wire-*), so changing a token restyles everything instantly (including across theme switches). - App CSS — redefine a
.wire-*class in your own stylesheet, which is loaded afterui.cssand therefore wins. classprop — pass aclassprop to a component; it is appended to the component's root element, letting you add per-instance classes without touching the base styles.wrnexus eject <name>— copy the component's.wrnsource into yourapp/components, where (because app components shadow library ones) you fully own and can edit it. UseuiComponentNames()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 WrNexus toolchain (Node is not supported).
- Peer packages: components are discovered and rendered by
@wrnexus/router(viacomponentDirs) and served by@wrnexus/dev-server/ built by@wrnexus/cli. - Depends on
@wrnexus/core(dependencies). theme-togglerelies on the framework's theme runtime, which binds thedata-wire-theme-toggleattribute — no per-component JS is required.