agentic-ui logoagentic-ui

Quick Start

Install @brijbyte/agentic-ui, wire up the CSS, and render your first component in under five minutes.

1. Install

Install the package and its peer dependencies:

pnpm add @brijbyte/agentic-ui @base-ui/react react react-dom
# or
npm install @brijbyte/agentic-ui @base-ui/react react react-dom
Peer deps: react ^19 and react-dom ^19.

2a. CSS setup — with Tailwind v4

Add after @import "tailwindcss" in your CSS entry file:

/* app/globals.css */
@import "tailwindcss";

/* Layer order is already established by tailwind */
@import "@brijbyte/agentic-ui/reset";
@import "@brijbyte/agentic-ui/tokens";
@import "@brijbyte/agentic-ui/tailwind-theme";

After this, every design token is a Tailwind utility: bg-canvas, text-primary, border-line, font-mono, rounded-md, shadow-sm

See all the available color, typography, spacing or other tokens.

layer-order.css establishes the layer order and theme.css places all design tokens in @layer theme. Resets land in @layer base — the lowest-priority layer, component styles in @layer components, and Tailwind utilities in @layer utilities (highest priority). tailwind-theme must be processed by @tailwindcss/vite or @tailwindcss/postcss.

2b. CSS setup — without Tailwind

Import the pre-built stylesheet once at your app entry:

/* Import once at the root of your app */
@import "@brijbyte/agentic-ui/styles";

Without Tailwind you have two options when bringing in the design-system CSS. Importing@brijbyte/agentic-ui/styles pulls tokens, reset, and every component bundle in one go — the simplest path but also the heaviest. If you want minimal CSS you can import just the base files (@brijbyte/agentic-ui/layer-order + @brijbyte/agentic-ui/reset + @brijbyte/agentic-ui/tokens) and opt into each component’s CSS separately, exactly like the per-component section describes.

The stylesheet is never injected automatically — component JS imports contain zero CSS side-effects. You control exactly where and when it loads.

CSS layer order

The cascade priority order is theme (lowest) → basecomponents utilities (highest):

  • @layer theme — design tokens (CSS custom properties). Lowest priority — everything beats them.
  • @layer base — element resets and Tailwind preflight. Beats tokens.
  • @layer components — component styles. Beats resets.
  • @layer utilities — Tailwind utilities. Beats everything.

This declaration is included in tokens.css, so importing tokens is sufficient in most setups. If you're importing component CSS without tokens — for example, using a pre-built button.css in isolation — import @brijbyte/agentic-ui/layer-order first:

/* Establishes the correct CSS cascade order.
   Already included in tokens.css — you only need this
   if you're importing component CSS without tokens. */

@import "@brijbyte/agentic-ui/layer-order";
CSS only honours the first time each layer name appears in an ordering statement. Subsequent declarations from tailwindcss or other files are harmless — the order is already fixed. Any unlayered :root override also beats all layers without needing !important.

Dark mode

Tokens adapt automatically via prefers-color-scheme. Override programmatically with data-theme on <html>:

document.documentElement.dataset.theme = "light"; // force light
document.documentElement.dataset.theme = "dark"; // force dark
delete document.documentElement.dataset.theme; // follow OS
Because @theme inline references live CSS variables, dark mode in Tailwind utilities switches automatically — no dark: prefix needed.

Using components

Import from the per-component path for tree-shaking, or from the barrel for convenience:

// Per-component (recommended — tree-shakable)
import { Button } from "@brijbyte/agentic-ui/button";
import { Badge } from "@brijbyte/agentic-ui/badge";
import { Input } from "@brijbyte/agentic-ui/input";
import { Drawer } from "@brijbyte/agentic-ui/drawer";

import "@brijbyte/agentic-ui/button.css";
import "@brijbyte/agentic-ui/badge.css";
import "@brijbyte/agentic-ui/input.css";
import "@brijbyte/agentic-ui/drawer.css";

// Barrel (convenient for prototyping)
import { Button, Badge, Input } from "@brijbyte/agentic-ui";

import "@brijbyte/agentic-ui/button.css";
import "@brijbyte/agentic-ui/badge.css";
import "@brijbyte/agentic-ui/input.css";
import { Button } from "@brijbyte/agentic-ui/button";
import { Input } from "@brijbyte/agentic-ui/input";

import "@brijbyte/agentic-ui/button.css";
import "@brijbyte/agentic-ui/input.css";

export function LoginForm() {
  return (
    <form>
      <Input placeholder="Email" type="email" />
      <Input placeholder="Password" type="password" />
      <Button variant="solid" type="submit">
        Sign in
      </Button>
    </form>
  );
}

If you find yourself importing the component CSS everywhere, create local wrappers that import the CSS once and re-export the component, ensuring you only load CSS for components you actually use, and point a tsconfig or bundler alias at those wrappers:

// tsconfig.json (or bundler alias)
{
  "compilerOptions": {
    "paths": {
      "@ui/*": ["./src/components/ui/*"]
    }
  }
}

// ./src/components/ui/accordion.ts
import '@brijbyte/agentic-ui/accordion.css';
export * from '@brijbyte/agentic-ui/accordion';

// usage
import { Accordion } from '@ui/accordion';

<Accordion ... />
Use your bundler’s alias feature (Webpack, Vite, etc.) instead if you don’t have tsconfig path mappings. Point the alias at the wrappers so only the reusable exports and CSS load.
All demos in these docs assume no aliasing and import the CSS for every component in each snippet, so you can follow them without setting up aliases first.

Composing with @base-ui/react

Every complex component exports individually-styled sub-parts. Mix them with raw @base-ui/react primitives for full control over structure and behaviour:

import * as BaseDialog from "@base-ui/react/dialog";
import { DialogBackdrop, DialogPopup, DialogTitle, DialogClose } from "@brijbyte/agentic-ui/dialog";

// Raw base-ui Root (controlled state, custom refs) +
// styled parts (design-system appearance)
<BaseDialog.Root open={open} onOpenChange={setOpen}>
  <BaseDialog.Portal>
    <DialogBackdrop />
    <BaseDialog.Viewport>
      <DialogPopup>
        <DialogTitle>Are you sure?</DialogTitle>
        <DialogClose>Cancel</DialogClose>
        <button onClick={onConfirm}>Confirm</button>
      </DialogPopup>
    </BaseDialog.Viewport>
  </BaseDialog.Portal>
</BaseDialog.Root>;
Styled parts are plain React components — they add scoped class names but manage no state. All accessibility and interaction logic lives in the @base-ui/react Root.

Accessing class names

Every component path exports a <Name>Styles object — the CSS module class name map. The keys are semantic names like root, variant-solid, or trigger-icon; the values are the hashed class strings the browser sees at runtime.

import { ButtonStyles } from "@brijbyte/agentic-ui/button";
import "@brijbyte/agentic-ui/button.css";

// ButtonStyles is a Record<string, string> — keys are the
// semantic names, values are the hashed CSS module class names.
//
// Available keys for Button:
//   root, variant-solid, variant-soft, variant-outline, variant-ghost,
//   tone-primary, tone-secondary, tone-destructive, tone-success,
//   tone-warning, size-xs, size-sm, size-md, size-lg, icon-only,
//   loader, loader-visible, spinner, content-loading

console.log(ButtonStyles.root);
//=> "root_a1b2c3"  (hashed at build time)

console.log(ButtonStyles["variant-solid"]);
//=> "variant-solid_x9y8z7"

Import from the per-component path or from the barrel:

import { ButtonStyles } from "@brijbyte/agentic-ui/button";
import { DialogStyles, DrawerStyles } from "@brijbyte/agentic-ui";

// In a test — assert a class was applied
expect(el.className).toContain(ButtonStyles.root);

// At runtime — read the hashed class name
const cls = ButtonStyles["variant-solid"]; // "variant-solid_a1b2c3d4"
el.classList.add(cls!);

// Other style maps are also available from the barrel
console.log(DialogStyles.content, DrawerStyles.backdrop);
The full list of available keys for each component is shown in the CSS Class Names section of its API Reference page.

Overriding styles — use the keys to target internal parts from your own CSS, or scope token overrides to a wrapper element:

/* Target a component's internal parts with the Styles object.
   Use :global() in a CSS module, or reference the hashed class
   directly in a plain stylesheet. */

/* Option 1: Override in a CSS module using :global() */
.my-toolbar :global(.root_a1b2c3) {
  border-radius: 999px;
}

/* Option 2: Use the Styles object in JS to build a selector */
/* const selector = `.${ButtonStyles.root}`;               */
/* document.querySelector(selector)?.classList.add("pill"); */

/* Option 3: Override tokens scoped to the component */
/* Every component reads design tokens — override them
   in a wrapper to retheme just that subtree. */
.branded-buttons {
  --color-accent: oklch(0.65 0.24 280);
  --color-accent-hover: oklch(0.60 0.24 280);
  --radius-md: 999px;
}
The recommended approach is option 3 — override design tokens on a wrapper. This survives class-name hash changes across versions. Direct class targeting (options 1 & 2) is brittle but useful for one-off fixes.

Testing — assert that a component rendered the expected variant or state class:

import { ButtonStyles } from "@brijbyte/agentic-ui/button";
import { render, screen } from "@testing-library/react";
import { Button } from "@brijbyte/agentic-ui/button";

// Assert a specific style variant was applied
const { container } = render(<Button variant="soft" />);
const btn = container.firstElementChild!;

expect(btn.className).toContain(ButtonStyles["variant-soft"]);
expect(btn.className).not.toContain(ButtonStyles["variant-solid"]);

// Query by the hashed class name
const root = container.querySelector(`.${ButtonStyles.root}`);
expect(root).toBeInTheDocument();

Per-component CSS

By default, @brijbyte/agentic-ui/styles ships all component CSS in one file (~60 kB unminified). If you only use a few components — or are building a micro-frontend — you can import only what you need. Every component has a parallel /<name>.css subpath that resolves to its own plain CSS file. The JS and CSS imports are always explicit and separate — no auto-injection.

Without Tailwind:

/* Instead of the full bundle… */
@import "@brijbyte/agentic-ui/styles";

/* …import only what you use: tokens + reset are always needed,
   then add one line per component. */
@import "@brijbyte/agentic-ui/layer-order";
@import "@brijbyte/agentic-ui/reset";
@import "@brijbyte/agentic-ui/tokens";
@import "@brijbyte/agentic-ui/button.css";
@import "@brijbyte/agentic-ui/input.css";
@import "@brijbyte/agentic-ui/dialog.css";

With Tailwind v4:

/* With Tailwind v4 */
@import "tailwindcss";
@import "@brijbyte/agentic-ui/tokens";
@import "@brijbyte/agentic-ui/reset";
@import "@brijbyte/agentic-ui/tailwind-theme";
@import "@brijbyte/agentic-ui/button.css";
@import "@brijbyte/agentic-ui/input.css";
@import "@brijbyte/agentic-ui/dialog.css";
tokens and reset are always required — they define the CSS custom properties every component style references. Component stylesheets are self-contained beyond that; you can add them in any order.

All available component CSS paths:

CSS importJS import
@brijbyte/agentic-ui/accordion.css@brijbyte/agentic-ui/accordion
@brijbyte/agentic-ui/alert-dialog.css@brijbyte/agentic-ui/alert-dialog
@brijbyte/agentic-ui/badge.css@brijbyte/agentic-ui/badge
@brijbyte/agentic-ui/button.css@brijbyte/agentic-ui/button
@brijbyte/agentic-ui/card.css@brijbyte/agentic-ui/card
@brijbyte/agentic-ui/checkbox.css@brijbyte/agentic-ui/checkbox
@brijbyte/agentic-ui/collapsible.css@brijbyte/agentic-ui/collapsible
@brijbyte/agentic-ui/context-menu.css@brijbyte/agentic-ui/context-menu
@brijbyte/agentic-ui/dialog.css@brijbyte/agentic-ui/dialog
@brijbyte/agentic-ui/drawer.css@brijbyte/agentic-ui/drawer
@brijbyte/agentic-ui/input.css@brijbyte/agentic-ui/input
@brijbyte/agentic-ui/menu.css@brijbyte/agentic-ui/menu
@brijbyte/agentic-ui/meter.css@brijbyte/agentic-ui/meter
@brijbyte/agentic-ui/number-field.css@brijbyte/agentic-ui/number-field
@brijbyte/agentic-ui/popover.css@brijbyte/agentic-ui/popover
@brijbyte/agentic-ui/progress.css@brijbyte/agentic-ui/progress
@brijbyte/agentic-ui/radio.css@brijbyte/agentic-ui/radio
@brijbyte/agentic-ui/radio-group.css@brijbyte/agentic-ui/radio-group
@brijbyte/agentic-ui/select.css@brijbyte/agentic-ui/select
@brijbyte/agentic-ui/separator.css@brijbyte/agentic-ui/separator
@brijbyte/agentic-ui/slider.css@brijbyte/agentic-ui/slider
@brijbyte/agentic-ui/switch.css@brijbyte/agentic-ui/switch
@brijbyte/agentic-ui/tabs.css@brijbyte/agentic-ui/tabs
@brijbyte/agentic-ui/toast.css@brijbyte/agentic-ui/toast
@brijbyte/agentic-ui/tooltip.css@brijbyte/agentic-ui/tooltip

Customising tokens

Re-declare any CSS variable after importing the stylesheet to override it globally:

@import "@brijbyte/agentic-ui/styles";

:root {
  --font-mono: "Cascadia Code", monospace;
  --color-accent-9: #7c3aed; /* purple accent */
  --radius-md: 2px; /* sharper corners */
}

Summary

1

Install

pnpm add @brijbyte/agentic-ui @base-ui/react react react-dom
2

Import CSS

/* With Tailwind v4 */
@import "tailwindcss";
@import "@brijbyte/agentic-ui/tokens";
@import "@brijbyte/agentic-ui/reset";
@import "@brijbyte/agentic-ui/tailwind-theme";

/* Without Tailwind, full styles */
@import "@brijbyte/agentic-ui/styles";

/* Without Tailwind, minimal styles */
@import "@brijbyte/agentic-ui/layer-order";
@import "@brijbyte/agentic-ui/reset";
@import "@brijbyte/agentic-ui/tokens";
/* Then, add component specific styles as needed, e.g. */
@import "@brijbyte/agentic-ui/button.css";
3

Render components

import { Button } from "@brijbyte/agentic-ui/button";

<Button variant="solid">Hello world</Button>;
4

Optionally compose with @base-ui/react

import { Drawer } from "@base-ui/react/drawer";
import { DrawerBackdrop, DrawerPopup } from "@brijbyte/agentic-ui/drawer";

<Drawer.Root swipeDirection="right">
  <Drawer.Portal>
    <DrawerBackdrop />
    <DrawerPopup side="right"></DrawerPopup>
  </Drawer.Portal>
</Drawer.Root>;