Skip to content

bvasilenko/vUi

Repository files navigation

vUi

Polymorphic React primitives. CVA variants, cn() class dedup, token bridge to vTheme. Semantic HTML defaults, ARIA inline, ref forwarding — no theme provider, no runtime config.

Install

npm install @booga/vui

Peer deps: react ^18, react-dom ^18, tailwindcss ^3.4.

Theme setup

vUi's components emit Tailwind color-role classes (bg-primary, border-input, …). Those roles are defined by @booga/vtheme. Apply its preset so they resolve:

// tailwind.config.js
import vtheme from "@booga/vtheme/preset";

export default {
  presets: [vtheme],
  content: [
    "./src/**/*.{ts,tsx}",
    "./node_modules/@booga/vui/dist/**/*.js",
  ],
};

Without the preset the role classes compile to nothing — components render unstyled.

Usage

import { Button, Card, CardContent, Input, cn } from "@booga/vui";

<Button variant="default" size="md">Save</Button>
<Button as="a" href="/docs">Docs</Button>
<Button asChild><a href="/docs">Docs</a></Button>

<Card>
  <CardContent>
    <Input defaultValue="hello" />
  </CardContent>
</Card>

cn("p-2", "p-4") // → "p-4"

Polymorphic as prop

Every component accepts as to change the rendered element. TypeScript narrows props to the target element type.

<Button as="a" href="/home">Link button</Button>
// → <a href="/home" class="...button classes...">Link button</a>

asChild / Slot composition

asChild delegates rendering to the immediate child, merging classes and props.

<Button asChild>
  <a href="/home">Link</a>
</Button>
// → <a href="/home" class="...button classes...">Link</a>

Variants (Button)

variant: default | secondary | destructive | outline | ghost | link
size: sm | md | lg | icon

Token bridge

Button's default variant references --v-color-accent from vTheme CSS variables. Set tokens at :root via cssVars(tokens) from @booga/vtheme.

Layout primitives

Box, Stack, Inline, Grid — flex/grid wrappers, polymorphic, extend via className.

Overlay components

Sheet, Dialog, Popover, Tooltip — compound components with ARIA defaults. Enhanced by vAria when installed.

<Sheet open={open} onOpenChange={setOpen}>
  <SheetTrigger>Open</SheetTrigger>
  <SheetContent aria-label="Panel">...</SheetContent>
</Sheet>

Contributing

Contributions follow the Contributor Covenant 2.1.

License

MIT © 2026 bvasilenko

About

My polymorphic React primitives. CVA variants, cn() dedup, vTheme token bridge. Semantic HTML, ARIA defaults, split-bundle ESM+CJS for tree-shaking.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors