Installation
@bridgee-ai/senna

Install Senna

Senna’s package identity is @bridgee-ai/senna. This initial version is available from the private source repository; it has not been published to npm.

Build it from source:

git clone git@github.com:bridgee-ai/senna.git
cd senna
corepack pnpm@10.22.0 install --frozen-lockfile
corepack pnpm@10.22.0 --filter @bridgee-ai/senna build

In a local consuming project, link the built component package:

pnpm add /absolute/path/to/senna/packages/kumo
pnpm add react react-dom @phosphor-icons/react

Use workspace:* when integrating it into a pnpm workspace. The npm and npx examples elsewhere in these docs describe the intended package interface once a maintainer publishes it; until then use pnpm senna from this checkout.

npm

npm install @bridgee-ai/senna

pnpm

pnpm add @bridgee-ai/senna

yarn

yarn add @bridgee-ai/senna

Install the peer dependencies if your project does not already provide them:

pnpm add react react-dom @phosphor-icons/react

Import Components

Import from the main package or use a granular component path:

import { Button, Input, LayerCard } from "@bridgee-ai/senna";
import { Dialog } from "@bridgee-ai/senna/components/dialog";

Senna is built on Base UI. Advanced applications can import the re-exported unstyled primitives:

import { Accordion, Popover, Slider } from "@bridgee-ai/senna/primitives";
import { Dialog } from "@bridgee-ai/senna/primitives/dialog";

Prefer Senna’s styled components when one is available. Base UI primitives are useful when building a component that Senna does not provide or when you need lower-level behavior and styling control.

Upstream Kumo Option

Senna is an independent fork of Cloudflare Kumo. The original upstream package remains available and is a supported provenance and compatibility reference:

pnpm add @cloudflare/kumo
import { Button } from "@cloudflare/kumo";
import "@cloudflare/kumo/styles";

Choose @bridgee-ai/senna for the Bridgee-maintained Senna release line. Choose @cloudflare/kumo when you specifically need Cloudflare’s upstream release line or are checking behavior against upstream. The packages have separate maintainers and release histories; use one import namespace consistently within an application.

Why Some Names Still Say Kumo

Senna deliberately preserves inherited names such as KumoPortalProvider, useKumoToastManager, KUMO_* constants, and kumo-* semantic classes. Those names are a compatibility namespace, not the current product name. Keeping them stable allows incremental migration and makes curated upstream commits easier to review.

For example, Senna package imports and inherited styling names are used together:

import { Button, KumoPortalProvider } from "@bridgee-ai/senna";

export function App() {
  return (
    <KumoPortalProvider>
      <Button className="bg-kumo-brand text-kumo-on-brand">Continue</Button>
    </KumoPortalProvider>
  );
}

Import Styles

Tailwind CSS v4

Import Senna’s theme before Tailwind and tell Tailwind to scan the package output. Import order matters.

/* app.css or main.css */
@source "../node_modules/@bridgee-ai/senna/dist/**/*.{js,jsx,ts,tsx}";
@import "@bridgee-ai/senna/styles/tailwind";
@import "tailwindcss";

Tailwind CSS v4 does not scan node_modules/ by default. Adjust the @source path relative to your CSS file or Senna components may render with missing utility styles.

The default @bridgee-ai/senna/styles export is equivalent to styles/tailwind.

Without Tailwind

Use the standalone stylesheet when the application does not run Tailwind:

import "@bridgee-ai/senna/styles/standalone";

Complete Example

/* app.css */
@source "../node_modules/@bridgee-ai/senna/dist/**/*.{js,jsx,ts,tsx}";
@import "@bridgee-ai/senna/styles/tailwind";
@import "tailwindcss";
import { Button, Input, LayerCard } from "@bridgee-ai/senna";
import "./app.css";

export default function App() {
  return (
    <LayerCard className="rounded-lg p-6">
      <h1 className="mb-4 text-2xl font-bold">Welcome to Senna</h1>
      <Input placeholder="Enter your name..." className="mb-4" />
      <Button variant="primary">Submit</Button>
    </LayerCard>
  );
}

Components and Blocks

Components are versioned npm exports:

import { Button, Dialog, Input } from "@bridgee-ai/senna";

Blocks are higher-level compositions installed as source code that your application owns:

npx @bridgee-ai/senna init
npx @bridgee-ai/senna blocks
npx @bridgee-ai/senna add PageHeader

See Components vs Blocks for ownership and customization guidance.

Utilities

import { cn, LinkProvider, safeRandomId } from "@bridgee-ai/senna";

const className = cn("base-class", condition && "conditional-class");
const id = safeRandomId();

<LinkProvider component={YourAppLink}>{/* Your application */}</LinkProvider>;