Skip to content

Installation

Install the package, import the stylesheet once, and wrap your app in FujiProvider. That is the whole setup; the guides below cover framework-specific entry points and styling details.

1. Install

bash
npm install @fujiui/react

2. Import styles and wrap your app

Import the stylesheet once at the top of your tree, then render everything inside one provider.

tsx
// app entry (layout, main, or root component)
import "@fujiui/react/styles.css";
import { FujiProvider, Button } from "@fujiui/react";

export default function App() {
  return (
    <FujiProvider defaultTheme="light" defaultRadius="cornered">
      <Button tone="forest">Save changes</Button>
    </FujiProvider>
  );
}

Peer dependencies and browser support

No other runtime dependencies - Base UI, class-variance-authority, clsx, and tailwind-merge are bundled, not peer dependencies you need to install yourself.

Peer dependencyRange
react^18.0.0 || ^19.0.0
react-dom^18.0.0 || ^19.0.0
BrowserSupport
Chrome / EdgeLast 2 versions
FirefoxLast 2 versions
Safari16+ (backdrop-filter support for the Glass theme)
iOS Safari / Chrome AndroidLast 2 versions

SSR, hydration, and Server Components

Every component renders identically on the server and client, so plain SSR/SSG works with no special setup. A Server Component may render a client compound as JSX (<Dialog>...</Dialog>) but must not access a static property on it (Dialog.Content) - import the named sub-export instead, or move that section behind a "use client" boundary. See Troubleshooting below for the exact error this produces.

Form validation with React Hook Form

Fuji form controls are plain controlled components (value / onChange), so they wire into React Hook Form's Controller the same way any custom input does.

Testing

Fuji doesn't ship a dedicated testing package. Components use real semantic HTML and standard ARIA roles/labels (buttons, dialogs, listboxes, etc.), so they work directly with role- and label-based queries in Testing Library (getByRole, getByLabelText) without needing custom test IDs.

Troubleshooting

Components render with no styling at all.

Cause: The stylesheet import (`import "@fujiui/react/styles.css"`) is missing or loaded after component CSS.

Fix: Import the stylesheet once, as early as possible in your entry file - before any of your own global CSS that might otherwise win the cascade.

The page flashes the wrong theme for a moment on load or refresh.

Cause: The provider mounted with its default theme before your persisted/preferred value was read.

Fix: Pass `persist` on the root `FujiProvider` so it reads the saved preference before first paint. For a Next.js app-shell, apply the persisted value with a small pre-hydration script in `<head>` (see this site's own `layout.tsx` for the pattern).

Build error: "Element type is invalid" when accessing e.g. `Dialog.Content` from a Server Component.

Cause: A Server Component did a static property access (Dialog.Content) on a client-compound import - Next.js replaces "use client" module exports with opaque client references that don't carry extra static properties.

Fix: Import the named sub-export directly (`import { DialogContent } from "@fujiui/react"`) or move that section behind a `"use client"` boundary.

React hydration mismatch warning involving a component that shows a date or "today".

Cause: Passing a raw `new Date()` computed during server render, which differs from the client's local time zone.

Fix: Compute a UTC-normalized date for the initial render (see the Calendar docs for the exact pattern) and correct to the visitor's local date in an effect after mount.

A Fuji class you added dynamically (e.g. building a className string at runtime) has no effect.

Cause: Tailwind's static scanner can't see class names that only exist at runtime as a concatenated string.

Fix: Use complete, literal class name strings (or the cn() helper with literal branches) so Tailwind's scanner can find them at build time.