Skip to content

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.

Team plan

Active
8 of 10
<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.

Terminal window
pnpm add @wovenui/core @wovenui/components

Prebuilt 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.

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

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.

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>

Pick one path: the bundle or per-component entries, never both. Shared rules would emit twice.

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

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.

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.

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.