Get started
WovenUI Components (@wovenui/components) is a set of CSS-first components built on the tokens of WovenUI core. It has no icons; tabs, toasts, autocomplete and data-table sorting add a small optional script. Components read core tokens (--wu-*), so they follow light, dark, inverse and high-contrast themes.
<article class="wu-card"> <header class="wu-card-header"> <h3 class="wu-card-title">Team plan</h3> <span class="wu-badge success">Active</span> </header> <div class="wu-card-body flex col gap-2"> <label class="wu-progress-label" for="overview-seats"><span>Seats used</span><span>8 of 10</span></label> <progress class="wu-progress" id="overview-seats" value="8" max="10">8 of 10</progress> </div> <footer class="wu-card-footer"> <button class="wu-btn" type="button">Manage seats</button> <button class="wu-btn brand" type="button">Invite</button> </footer></article>The layout classes in the examples (flex, col, gap-2 and the like) are core utility classes, not part of the kit.
Install
Section titled “Install”pnpm add @wovenui/core @wovenui/componentsPrebuilt CSS, loaded after core:
<link rel="stylesheet" href="node_modules/@wovenui/core/dist/wovenui.min.css"><link rel="stylesheet" href="node_modules/@wovenui/components/dist/wovenui-kit.min.css">From source, through a bundler (Vite, webpack), which resolves the package URLs with no setup:
@use "@wovenui/core";@use "@wovenui/components";The kit emits only its own rules. Core still provides the tokens and base styles, once, in the global stylesheet.
Naming
Section titled “Naming”- The component root carries the
wu-prefix:wu-btn. - Modifiers are bare words, valid only together with the root:
wu-btn brand sm. The CSS emits them as compounds (.wu-btn.brand), never alone. - Parts use the root name plus a part:
wu-card-header. - A modifier word never reuses a core class name.
<button class="wu-btn brand sm" type="button">Save</button>Animations are opt-in
Section titled “Animations are opt-in”Components are calm by default. Turn motion on per component with the word animated, or for a page or section with wu-animated on an ancestor:
<button class="wu-btn brand animated" type="button">Save</button>
<body class="wu-animated">...</body>Motion runs only under prefers-reduced-motion: no-preference, so reduced motion always wins.
Right to left
Section titled “Right to left”Components use logical properties, so they follow dir="rtl" with no extra classes. Arrows the kit draws itself, such as the breadcrumb chevron and the pagination arrows, turn on their own.
Your own directional icons (back, next, arrows) need one word: wu-mirror flips the element horizontally in right to left. It works on an <svg>, an <img> or an icon font element, and leaves left to right untouched. See Right to left for the full page, with Arabic and Hebrew screens.
<a class="wu-btn" href="#"><svg class="wu-mirror" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M10 3 5 8l5 5" fill="none" stroke="currentColor" stroke-width="2"/></svg>رجوع</a>Two ways to load components
Section titled “Two ways to load components”Pick one path: the bundle or per-component entries, never both. Shared rules would emit twice.
The bundle, with $components
Section titled “The bundle, with $components”Every component is on by default. Turn one off in the bundle:
@use "@wovenui/components" with ($components: ("button": false));A component that needs another one stops the compile with an error naming both when the needed one is off. The components that need another one:
| Component | Needs |
|---|---|
btn-group |
button |
avatar-group |
avatar |
pagination |
button |
confirm-modal |
modal, button |
autocomplete |
input |
data-table |
table |
Per-component entries
Section titled “Per-component entries”For CSS modules and component <style> blocks, load one component with what it needs, in the same layer order:
@use "@wovenui/components/button";Each entry also emits the shared kit values (:root custom properties such as --wu-kit-ease-spring), so a component never reads a missing value.
Layers
Section titled “Layers”The kit declares @layer reset, base, components, recipes;, the core order plus recipes. Every component lives in @layer components. Utility classes and app CSS stay unlayered and win without !important.
An unlayered reset in your own CSS, such as button { font: inherit }, beats every layered rule, kit components included. Put such resets in a layer before components.
Sass CLI without a bundler
Section titled “Sass CLI without a bundler”The Sass CLI does not resolve plain package URLs: --pkg-importer=node covers only pkg: URLs, and the kit loads @wovenui/core/mixins without one. Without a bundler, use the prebuilt CSS.