Installation

Install @voila.dev/ui, point Tailwind at it, and render your first component.

  1. Install the core and the tokens.

    bun add @voila.dev/ui

    The peers are react@19, react-dom@19 and tailwindcss@4. Your app almost certainly has the first two already.

  2. Import the stylesheet.

    In the CSS entry point your app already loads:

    src/styles/globals.css
    @import "tailwindcss";
    @import "@voila.dev/ui/styles/globals.css";
    @import "@voila.dev/ui/styles/themes/default.css";

    The first import covers the token contract, the animation utilities, and — this is the part people expect to have to configure — telling Tailwind to scan the package. The package declares its own sources, so you never write a path into node_modules, and every domain (chart, map, filter…) is covered by the same import.

    The second picks the values. default is black and white; indigo, iris, sand, emerald and olive also ship. Exactly one theme, and it comes second — see Theming.

  3. Render something.

    src/app.tsx
    import { Button } from "@voila.dev/ui/button";
     
    export function App() {
    	return <Button>Ship it</Button>;
    }

Import paths

Every component is its own entry point, named after its file:

import { Button } from "@voila.dev/ui/button";
import { Dialog } from "@voila.dev/ui/dialog";
import { cn } from "@voila.dev/ui/utils";
import { useIsMobile } from "@voila.dev/ui/hooks";

There is no barrel export on purpose. A barrel would pull every component into the module graph of any file that imports one, which costs you both bundle size and dev-server cold start.

Dark mode

The tokens define a full dark palette under a .dark class. Put that class on <html> (or any ancestor) and everything below it switches:

document.documentElement.classList.toggle("dark", prefersDark);

If your app keys dark mode off something else — a data-theme attribute, say — redefine the variant once in your CSS:

@custom-variant dark (&:is([data-theme="dark"] *));

Verifying the install

If components render but look unstyled, an @import is missing — the package whose classes are absent has not been imported, so Tailwind never scanned it. If the import throws, check that your bundler resolves package exports (anything modern does) and that TypeScript is on "moduleResolution": "bundler".

Next: Theming and tokens.