Package Exports
- @nano-ui-kit/web-components
- @nano-ui-kit/web-components/components
- @nano-ui-kit/web-components/components/accordion
- @nano-ui-kit/web-components/components/action-list
- @nano-ui-kit/web-components/components/agent-artifact
- @nano-ui-kit/web-components/components/agent-feedback-bar
- @nano-ui-kit/web-components/components/agent-questions
- @nano-ui-kit/web-components/components/agent-reasoning
- @nano-ui-kit/web-components/components/agent-suggestions
- @nano-ui-kit/web-components/components/agent-trace
- @nano-ui-kit/web-components/components/alert
- @nano-ui-kit/web-components/components/avatar
- @nano-ui-kit/web-components/components/badge
- @nano-ui-kit/web-components/components/block
- @nano-ui-kit/web-components/components/breadcrumb
- @nano-ui-kit/web-components/components/button
- @nano-ui-kit/web-components/components/calendar-picker
- @nano-ui-kit/web-components/components/canvas
- @nano-ui-kit/web-components/components/card
- @nano-ui-kit/web-components/components/chart
- @nano-ui-kit/web-components/components/chat
- @nano-ui-kit/web-components/components/check
- @nano-ui-kit/web-components/components/code
- @nano-ui-kit/web-components/components/col
- @nano-ui-kit/web-components/components/color-picker
- @nano-ui-kit/web-components/components/command
- @nano-ui-kit/web-components/components/description-list
- @nano-ui-kit/web-components/components/divider
- @nano-ui-kit/web-components/components/drawer
- @nano-ui-kit/web-components/components/embed
- @nano-ui-kit/web-components/components/empty-state
- @nano-ui-kit/web-components/components/field
- @nano-ui-kit/web-components/components/grid
- @nano-ui-kit/web-components/components/heatmap
- @nano-ui-kit/web-components/components/icon
- @nano-ui-kit/web-components/components/image
- @nano-ui-kit/web-components/components/input
- @nano-ui-kit/web-components/components/inspector
- @nano-ui-kit/web-components/components/kbd
- @nano-ui-kit/web-components/components/list
- @nano-ui-kit/web-components/components/menu
- @nano-ui-kit/web-components/components/modal
- @nano-ui-kit/web-components/components/noodles
- @nano-ui-kit/web-components/components/option-card
- @nano-ui-kit/web-components/components/otp-input
- @nano-ui-kit/web-components/components/pagination
- @nano-ui-kit/web-components/components/pane
- @nano-ui-kit/web-components/components/pipeline-status
- @nano-ui-kit/web-components/components/popover
- @nano-ui-kit/web-components/components/progress
- @nano-ui-kit/web-components/components/progress-row
- @nano-ui-kit/web-components/components/radio
- @nano-ui-kit/web-components/components/range
- @nano-ui-kit/web-components/components/rating
- @nano-ui-kit/web-components/components/richtext
- @nano-ui-kit/web-components/components/row
- @nano-ui-kit/web-components/components/search
- @nano-ui-kit/web-components/components/segment
- @nano-ui-kit/web-components/components/segmented
- @nano-ui-kit/web-components/components/select
- @nano-ui-kit/web-components/components/skeleton
- @nano-ui-kit/web-components/components/slider
- @nano-ui-kit/web-components/components/stack
- @nano-ui-kit/web-components/components/stat
- @nano-ui-kit/web-components/components/stepper
- @nano-ui-kit/web-components/components/stream
- @nano-ui-kit/web-components/components/swiper
- @nano-ui-kit/web-components/components/switch
- @nano-ui-kit/web-components/components/table
- @nano-ui-kit/web-components/components/table-toolbar
- @nano-ui-kit/web-components/components/tabs
- @nano-ui-kit/web-components/components/tag
- @nano-ui-kit/web-components/components/text
- @nano-ui-kit/web-components/components/textarea
- @nano-ui-kit/web-components/components/timeline
- @nano-ui-kit/web-components/components/toast
- @nano-ui-kit/web-components/components/toggle-group
- @nano-ui-kit/web-components/components/toolbar
- @nano-ui-kit/web-components/components/tooltip
- @nano-ui-kit/web-components/components/tree
- @nano-ui-kit/web-components/components/upload
- @nano-ui-kit/web-components/core
- @nano-ui-kit/web-components/core/anchor
- @nano-ui-kit/web-components/core/controller
- @nano-ui-kit/web-components/core/data-stream
- @nano-ui-kit/web-components/core/data-stream.test
- @nano-ui-kit/web-components/core/element
- @nano-ui-kit/web-components/core/element.test
- @nano-ui-kit/web-components/core/form
- @nano-ui-kit/web-components/core/icons
- @nano-ui-kit/web-components/core/icons-manifest
- @nano-ui-kit/web-components/core/index
- @nano-ui-kit/web-components/core/markdown
- @nano-ui-kit/web-components/core/polyfills
- @nano-ui-kit/web-components/core/provider
- @nano-ui-kit/web-components/core/signals
- @nano-ui-kit/web-components/core/streams-bridge
- @nano-ui-kit/web-components/core/template
- @nano-ui-kit/web-components/core/transport
- @nano-ui-kit/web-components/css
- @nano-ui-kit/web-components/package.json
- @nano-ui-kit/web-components/patterns
- @nano-ui-kit/web-components/patterns/a2ui-root
- @nano-ui-kit/web-components/patterns/app-nav
- @nano-ui-kit/web-components/patterns/app-nav-group
- @nano-ui-kit/web-components/patterns/app-nav-item
- @nano-ui-kit/web-components/patterns/app-shell
- @nano-ui-kit/web-components/patterns/gen-ui
- @nano-ui-kit/web-components/patterns/nano-chat
- @nano-ui-kit/web-components/patterns/nano-editor
- @nano-ui-kit/web-components/patterns/section-nav
- @nano-ui-kit/web-components/patterns/section-nav-group
- @nano-ui-kit/web-components/patterns/section-nav-item
- @nano-ui-kit/web-components/styles/README.md
- @nano-ui-kit/web-components/styles/colors/index.css
- @nano-ui-kit/web-components/styles/colors/parameters.css
- @nano-ui-kit/web-components/styles/colors/primitives-accent.css
- @nano-ui-kit/web-components/styles/colors/primitives-brand.css
- @nano-ui-kit/web-components/styles/colors/primitives-danger.css
- @nano-ui-kit/web-components/styles/colors/primitives-info.css
- @nano-ui-kit/web-components/styles/colors/primitives-neutral.css
- @nano-ui-kit/web-components/styles/colors/primitives-shared.css
- @nano-ui-kit/web-components/styles/colors/primitives-success.css
- @nano-ui-kit/web-components/styles/colors/primitives-warning.css
- @nano-ui-kit/web-components/styles/colors/primitives.css
- @nano-ui-kit/web-components/styles/colors/scrims.css
- @nano-ui-kit/web-components/styles/colors/semantics.css
- @nano-ui-kit/web-components/styles/colors/surfaces.css
- @nano-ui-kit/web-components/styles/components.css
- @nano-ui-kit/web-components/styles/editorial.css
- @nano-ui-kit/web-components/styles/fonts.css
- @nano-ui-kit/web-components/styles/layouts/admin.css
- @nano-ui-kit/web-components/styles/prose.css
- @nano-ui-kit/web-components/styles/resets.css
- @nano-ui-kit/web-components/styles/themes.css
- @nano-ui-kit/web-components/styles/tokens.css
- @nano-ui-kit/web-components/styles/typography.css
- @nano-ui-kit/web-components/traits
- @nano-ui-kit/web-components/traits/active-state
- @nano-ui-kit/web-components/traits/anchor-positioning
- @nano-ui-kit/web-components/traits/attention-pulse
- @nano-ui-kit/web-components/traits/confetti
- @nano-ui-kit/web-components/traits/confetti-burst
- @nano-ui-kit/web-components/traits/count-up
- @nano-ui-kit/web-components/traits/define
- @nano-ui-kit/web-components/traits/dirty-state
- @nano-ui-kit/web-components/traits/drag-ghost
- @nano-ui-kit/web-components/traits/draggable
- @nano-ui-kit/web-components/traits/fade-presence
- @nano-ui-kit/web-components/traits/focus-trap
- @nano-ui-kit/web-components/traits/focusable
- @nano-ui-kit/web-components/traits/glow-focus
- @nano-ui-kit/web-components/traits/gradient-shift
- @nano-ui-kit/web-components/traits/haptic-feedback
- @nano-ui-kit/web-components/traits/hotkey
- @nano-ui-kit/web-components/traits/hoverable
- @nano-ui-kit/web-components/traits/index
- @nano-ui-kit/web-components/traits/inertia-drag
- @nano-ui-kit/web-components/traits/intersection-observer
- @nano-ui-kit/web-components/traits/keyboard-nav
- @nano-ui-kit/web-components/traits/magnetic-hover
- @nano-ui-kit/web-components/traits/noise-texture
- @nano-ui-kit/web-components/traits/parallax
- @nano-ui-kit/web-components/traits/portal
- @nano-ui-kit/web-components/traits/pressable
- @nano-ui-kit/web-components/traits/resizable
- @nano-ui-kit/web-components/traits/resize-observer
- @nano-ui-kit/web-components/traits/ripple
- @nano-ui-kit/web-components/traits/roving-tabindex
- @nano-ui-kit/web-components/traits/scale-press
- @nano-ui-kit/web-components/traits/scroll-lock
- @nano-ui-kit/web-components/traits/shimmer-loading
- @nano-ui-kit/web-components/traits/snap-to-grid
- @nano-ui-kit/web-components/traits/sound-feedback
- @nano-ui-kit/web-components/traits/spring-animate
- @nano-ui-kit/web-components/traits/tilt-hover
- @nano-ui-kit/web-components/traits/tossable
- @nano-ui-kit/web-components/traits/typeahead
- @nano-ui-kit/web-components/traits/typewriter
- @nano-ui-kit/web-components/traits/validation
Readme
@nano-ui-kit/web-components
Vanilla web components + A2UI runtime for NanoUI. 80 light-DOM custom elements, a reactive core, a trait system, and a renderer that turns A2UI protocol messages into live DOM.
This package ships UI atoms only. The generation pipeline lives in
@nano-ui-kit/a2ui-compose; the pattern corpus in@nano-ui-kit/a2ui-corpus; the MCP server in@nano-ui-kit/a2ui-mcp.
Quick start
<link rel="stylesheet" href="node_modules/@nano-ui-kit/web-components/index.css" />
<script type="module">
import '@nano-ui-kit/web-components'; // registers every *-n tag
</script>
<card-n>
<header>
<span slot="icon"><avatar-n icon="user"></avatar-n></span>
<span slot="heading"><text-n strong>Hello</text-n></span>
</header>
<section>Composition works out of the box — no framework.</section>
</card-n>The package sideEffects entry keeps the import above from being
tree-shaken; importing index.js side-effect-registers every component.
Layout
web-components/
├── core/ — Reactivity + base classes
│ ├── signals.js signal() / computed() / effect() / batch() / untracked()
│ ├── template.js tagged templates: html, css, repeat, stamp
│ ├── element.js NanoElement — light-DOM reactive base
│ ├── form.js NanoFormElement — form-associated + validation
│ ├── provider.js global provider registration + router-n
│ ├── anchor.js popover + anchor-positioning
│ ├── markdown.js lightweight markdown renderer
│ └── transport.js SSE / streaming helpers for LLM adapters
│
├── components/ — 80 *-n custom elements
│ └── <tag>/
│ ├── <tag>.js class definition (extends NanoElement)
│ ├── <tag>.css @scope(tag-n) two-block: tokens + styles
│ ├── <tag>.yaml authoring contract (props, slots, events, examples)
│ └── <tag>.a2ui.json generated — do NOT edit
│
├── patterns/ — Higher-level compositions (tag: `nano-*`)
│ ├── app-shell, app-nav, section-nav — admin layout scaffolding
│ ├── nano-chat, nano-editor, gen-ui — LLM + editor + gen-UI patterns
│ └── index.js — registers all patterns
│
├── traits/ — 40 composable behaviors via defineTrait()
│ (pressable, focusTrap, confetti, resizable, …)
│
└── styles/ — Global tokens and CSS layering
├── tokens.css all --n-* design tokens
├── colors/ primitives / semantics / scrims
├── typography.css, space.css, radius.css, shadow.css
└── themes/*.css 8 themes (ocean, forest, sunset, …)The A2UI runtime (renderer, registry, wiring engine) lives in
@nano-ui-kit/a2ui-utils — installed as a dep; imported
from patterns/a2ui-root/a2ui-root.js. LLM transport lives in
@nano-ui-kit/gateway — the nano-chat pattern imports the
browser adapters from there. Build + training scripts live at the repo
root (/scripts), not in this package.
Component contract
Every component is a single-file class extending NanoElement (or
NanoFormElement for form fields). All styling lives in a sibling .css
file using two-block @scope:
@scope (button-n) {
:where(:scope) {
/* Tokens only — zero specificity, parent overrides win */
--button-bg: var(--n-accent-bg);
--button-fg: var(--n-accent-fg);
--button-radius: var(--n-radius);
}
:scope {
/* Styles — consume component tokens only, never global directly */
background: var(--button-bg);
color: var(--button-fg);
border-radius: var(--button-radius);
}
:scope[variant="danger"] {
--button-bg: var(--n-danger-bg); /* variants override tokens, not styles */
}
}Authoring rules (enforced by coherence-audit):
- No raw colors in component CSS — every color goes through a token.
- Variants change tokens, modes change layout. A selector that sets
display,padding,flex,grid, etc. is a mode and needs a Sanctioned Mode Attributes entry in the contract doc. - Boolean props default to
false. If the expected default is "on", flip the name (closable→permanent). - Event listeners in
connected()have matchingremoveEventListenerindisconnected(). Handlers are stable#fieldarrows, never inline. - Light DOM only. No
::part(),::slotted(), shadow roots. Use attribute selectors on children::scope > [slot="icon"].
Full authoring contract: docs/specs/component-token-contract.md.
The nano-ui-author skill encodes the 20 non-negotiable rules.
Card-n / drawer-n composition parity
Both accept bare <header> / <section> / <footer> tags OR explicit
[slot="header|body|footer"]. Both activate a 3-column header grid when
any direct [slot="icon|heading|description|action"] child is present
(:has(> …) — direct-child only). Drawer supports multi-section bodies
with sticky header/footer. See the drawer component page for worked
examples.
A2UI runtime
import { A2UIRenderer } from '@nano-ui-kit/a2ui-utils';
const renderer = new A2UIRenderer({ target: document.getElementById('canvas') });
renderer.apply({
type: 'updateComponents',
components: [
{ id: 'root', component: 'Card', children: ['hdr', 'body'] },
{ id: 'hdr', component: 'Header', slots: { heading: 'Generated UI' } },
{ id: 'body', component: 'Section', children: ['btn'] },
{ id: 'btn', component: 'Button', attrs: { variant: 'primary' }, content: 'Click' },
],
});Accepts the four A2UI message kinds: updateComponents,
updateDataModel, wireComponents, createSurface. The registry
normalizes LLM-emitted aliases (e.g. Carousel → swiper-n) so generated
output is robust to name drift.
Build
npm run build:components # regenerate all .a2ui.json from YAMLThe build also writes packages/a2ui/corpus/catalog-a2ui_0_9.json and
catalog-a2ui_0_9_rules.txt — the flat-file catalog the MCP server and
generation engine consume.
Themes, density, scale
<div data-theme="ocean" density="compact" size="sm">
…all descendants re-theme / re-densify / re-scale automatically…
</div>[data-theme]— 8 themes:default,ocean,forest,sunset,lavender,rose,slate,midnight[density]—compact(0.85×) ·spacious(1.15×)[size]—sm|md|lgshifts the entire typescale + component dimensions[radius]—sharp(0) ·rounded(1) ·round(2)
Each is a CSS-variable override; no class toggles, no re-imports.
Dependency direction
gen-ui ──reads──> a2ui-corpus ←─reads── web-components
a2ui-mcp ──reads──> gen-ui, a2ui-corpusWeb-components never imports from gen-ui or a2ui-mcp. The A2UI renderer consumes a protocol, not a generator — anything that emits valid A2UI messages drives it.
License
MIT