UI primitives with clean ownership.

Wensity UI primitives are foundational React controls for forms, selection, feedback, navigation, and layout. They live under /primitives so search engines, users, and the command palette all resolve each primitive to one canonical detail route.

Use this guide when you want Button, Input, Toggle, Dialog, Breadcrumb, Table, or any other of the 56 primitives as source in your app. For composed product UI (Agentic AI, SaaS blocks, Show Off, and related categories), keep using the Components guide and /components.

What primitives are

Foundation layer

Primitives are the small controls and layout pieces that larger Wensity components depend on.

Same source model

A primitive installs as a local .tsx file through the same Wensity registry contract as components.

Canonical catalog

The public catalog is /primitives, and each detail page uses /primitives/<slug>.

Owned in your repo

After install, the primitive is application code. Your formatter, linter, and git diff own the change.

Canonical routes

Primitive detail pages should be linked as /primitives/<slug>. Do not link primitive details through /components/<slug>, because the primitive route owns the canonical metadata, Open Graph URL, sitemap entry, and structured data.

One primitive, one public detail route

Use /primitives/button for the Button primitive, /primitives/input for the Input primitive, and /docs/primitives for the install workflow. Keep /components focused on composed product UI.

Install with CLI

Configure icons, radius, fonts, and control-solid colors once with the Create preset studio, then run the generated init --preset or apply --preset command. Or initialise with defaults:

terminal
$pnpm dlx wensity init
terminal
$pnpm dlx wensity add button

The CLI reads wensity.json, writes source into your configured components path, adds helper files when needed, rewrites internal imports to your aliases, applies stored primitive style (CSS + Tabler/Lucide), and installs declared package dependencies.

app/page.tsx
import { Button } from "@/components/wensity/button";
export default function Page() {
return (
<main className="grid min-h-screen place-items-center">
<Button>Continue</Button>
</main>
);
}

CLI vs shadcn

Wensity CLIPublic shadcn registry (@wensity/*)
Stored presets (wensity.json style)YesNo
Lucide deliveryYes, install-time transformNo, Tabler-canonical only
Full editable sourceYesYes
@wensity/ui runtimeNeverNever
Base UI dependencyOrdinary local npm depOrdinary local npm dep
Premium /componentsOutside primitive presetsNot exported

These are complementary paths, not feature parity. Prefer the Wensity CLI when you need presets or Lucide. Prefer shadcn when you already use shadcn registry tooling and only need a free Tabler primitive.

shadcn registry

Free primitives can also be installed through the public shadcn registry namespace.

terminal
$pnpm dlx shadcn@latest add @wensity/button

Use the Wensity CLI when you want the full Wensity config flow. Use shadcn when you already run a shadcn registry workflow and only need a quick free primitive add.

Manual source

The Code tab on each primitive detail page includes the install command, dependencies, full source, and usage snippet. Manual source is best for review. The CLI is better for repeatable team installs because it follows wensity.json and keeps helper paths consistent.

Theming

Primitives read the same Tailwind v4 tokens as Wensity components. Set the surface, border, foreground, muted foreground, and chili brand tokens once in your global CSS. Every primitive will inherit the same visual system.

Theme primitives and components together

Do not maintain a second primitive theme. Use the shared Wensity tokens from the Theming guide so Button, Input, Dialog, and larger components stay visually aligned.

Tokens & configuration

Installing a primitive writes two delimited blocks into your configured Tailwind CSS file: a Wensity Base Tokens block holding the semantic layer (--background, --foreground, --border, --muted*, --surface*) that the primitives paint with, and a Wensity Primitive Tokens block holding the --primitive-* namespace. shadcn installs receive the same values through cssVars / css on the registry item. Both blocks are replaced in place on re-run, and together they are the only configuration seam today: there is no runtime theme provider, settings UI, or per-primitive option graph.

Role familyExamplesWhat it controls
Surfaces--primitive-surface-elevated, --primitive-surface-overlaySolid panel / popup fills (no gradients, no parchment)
Controls--primitive-control-solid*, --primitive-control-height-*Button/toggle fills and sm/md/lg heights
Status--primitive-success, --primitive-warning, --primitive-info, --primitive-destructive*Alert/toast/badge intents
Radius--primitive-radius (+ derived control/surface/item)One base radius; derived roles use max(0px, calc(...))
Type--primitive-font-sans, --primitive-font-display, --primitive-font-monoTypography roles on primitives
Overlay--primitive-shadow-*, --primitive-backdrop, z-scale notesModal / popover / toast stacking

Future color, radius, font, or density presets only override these named variables in the delivered CSS block. Icon package selection is a CLI-time named-import transform for primitives, configure it with the Create preset studio.

Open-code contract: after wensity add <slug>, import from @/components/wensity/<slug> only. Installed files must not reference @wensity/ui. Behavioral packages such as @base-ui/react, framer-motion, gsap, ogl, and @tabler/icons-react (or lucide-react when selected) are normal npm dependencies in your app, not Wensity lock-in.

Slug note: text-area and empty-state are the canonical install slugs (kept for URL/CLI stability). Ecosystem aliases such as textarea / empty are a future option only, the CLI does not resolve aliases today.

When to use primitives