Theming
Fuji UI appearance is shaped by four global settings on FujiProvider: a theme, a material, a radius, and an elevation. Set them once and every component follows, because each reads the same design tokens rather than branching on the appearance in JavaScript. This page covers all four settings plus the colors, tokens, and shadows they drive.
Theme
There are two themes: light (default) and dark. The theme sets the page background, foreground, border, and tone colors. Set it once, globally; there is no per-component theme prop.
import { FujiProvider } from "@fujiui/react";
<FujiProvider
persist
defaultTheme="dark"
defaultMaterial="glass"
defaultRadius="soft"
defaultElevation="floating"
>
<App />
</FujiProvider>Each of the four settings can be controlled (theme, material, radius, elevation) or uncontrolled (defaultTheme, defaultMaterial, and so on), with a matching onThemeChange, onMaterialChange, onRadiusChange, or onElevationChange callback, and all four are exposed through useFujiConfig(). With persist, the provider saves them together as one preference under the fuji-appearance key, so a choice survives navigation, a new tab, and refresh. A preference saved by an older version as {"theme":"glass"} is read as dark + glass.
These swatches read the active appearance live
Every swatch reads its color directly from the active theme and material. Use the theme and glass controls in the header to watch them change without a page reload.
Background
--fuji-background
Background (subtle)
--fuji-background-subtle
Surface (subtle)
--fuji-surface-subtle
Surface
--fuji-surface
Surface (strong)
--fuji-surface-strong
Surface (overlay)
--fuji-surface-overlay
Foreground
--fuji-foreground
Foreground (muted)
--fuji-foreground-muted
Foreground (subtle)
--fuji-foreground-subtle
Default
--fuji-default
Border
--fuji-border
How appearance switching works
FujiProvider stamps data-fuji-theme, data-fuji-material, data-fuji-radius, and data-fuji-elevation on its root element, and the root provider (the one with persist) mirrors them onto <html> for native form control and color-scheme support. Every token is scoped under those attributes, so flipping one re-resolves every affected value in a single paint, with no remount and no React state threaded through the tree. Overlays such as dialogs, menus, popovers, and tooltips render in a portal outside the provider subtree; each Fuji UI overlay re-stamps all four attributes on its portalled root, so overlay content always matches the active appearance.
Material
Material is the second global axis: solid (default) or glass. It is independent of the theme, so dark mode and glass combine freely. Glass layers translucency and backdrop blur over whichever theme is active instead of bringing a palette of its own: the background, foreground, and tone colors still come from the theme.
import { FujiProvider } from "@fujiui/react";
// Light theme + glass: frosted light glass with dark text
<FujiProvider theme="light" material="glass">
<App />
</FujiProvider>
// Dark theme + glass: dark glass with light text
<FujiProvider theme="dark" material="glass">
<App />
</FujiProvider>The theme is the glass tint
Glass has no tint setting of its own: a light theme gives light glass and a dark theme gives dark glass. To tint one region differently from the rest of the page, such as a bright photo section in a dark app, nest a provider around just that region with the theme the glass should read as. Nested providers do not inherit material, so declare it again alongside theme.
import { FujiProvider } from "@fujiui/react";
<FujiProvider theme="dark" material="glass">
<App>
<FujiProvider theme="light" material="glass">
<BrightPhotoSection />
</FujiProvider>
</App>
</FujiProvider>What gets the material
Glass is for surfaces that sit over other content. Cards and panels, chrome such as Sidebar and Pagination, and overlays such as dialogs, drawers, menus, popovers, selects, and toasts take the translucent tint and backdrop blur. Buttons, fields, switches, sliders, and the rest of the control layer stay solid, so they read against the glass surface instead of competing with it, and a form never pays for one blur layer per input.
Backdrops
Glass composites over whatever is behind it. By default that is the active theme's own flat background. Add the shipped fuji-glass-atmosphereclass to an app root or panel for Fuji UI's gradient backdrop; it applies only under glass, so it is safe to render unconditionally. Your own photo, brand gradient, or color works too. Behind arbitrary or user-supplied imagery, put text on --fuji-surface or --fuji-surface-raised rather than --fuji-surface-subtle.
Fallbacks and accessibility
When backdrop-filter is unsupported, or the user has prefers-reduced-transparency: reduce set, glass surfaces fall back to opaque panels instead of a blurred effect; readability always wins over the visual effect. Print styles similarly flatten every theme to plain black on white.
Radius
Radius is the third global axis: cornered (default) or soft. It controls three scoped tokens (control, panel, and overlay radius), so every button, card, and dialog stays visually consistent with each other.
import { FujiProvider } from "@fujiui/react";
<FujiProvider radius="soft">
<App />
</FujiProvider>Cornered
control 6px · panel 10px · overlay 14px
Soft
control 14px · panel 20px · overlay 26px
Circular elements stay circular. Avatars, radio dots, switches, and status dots use rounded-full directly; radius tokens only apply to rectangular controls, panels, and overlays, never to semantically circular shapes.
Elevation
Elevation is the fourth global axis: regular (default) or floating. regular keeps the restrained shadows shown below. floating swaps in deeper, softly layered shadows plus a small inset highlight at meaningful boundaries such as cards, panels, menus, and overlays. It changes shadow depth only; it never adds scale or hover motion to static surfaces. In dark mode, floating uses deeper, darker layered shadows with a subtle inset highlight so raised surfaces still read against the near black canvas. Both modes drive the same shadow tokens, so every elevated component follows the mode automatically.
control floating
card floating
panel floating
overlay floating
Colors and tokens
Every color is a CSS custom property prefixed --fuji-, scoped per theme and material in the package stylesheet. Components reference these tokens, never raw hex values, through matching Tailwind utilities such as bg-fuji-surface-strong.
Surface hierarchy
Four surface levels express depth without relying on shadow alone: subtle for hover areas and inactive tabs, the base surface for cards and panels, strong for inputs and selected states, and overlay for dialogs, drawers, menus, popovers, and tooltips. Shadow depth is the separate elevation setting described above.
ComponentTone vs. StatusTone
Fuji UI has two separate tone vocabularies, and they are not interchangeable. ComponentTone (default | fire | water | forest | sun) is purely decorative - it powers Button, IconButton, ButtonGroup, Badge, Icon, Slider, Rating, Avatar, and similar visual-only tone props. Choosing tone="fire" on a Badge says nothing about status - it is a look, the same as picking a color swatch.
StatusTone (default | success | warning | danger | info) is semantic - the value itself carries meaning for accessibility, and it never changes regardless of the decorative palette in use. It is used by Alert, Toast, Result, StatusIndicator, Progress, CircularProgress, and Timeline, always through a variant prop rather than tone. Each status name maps internally onto one decorative token purely for styling: success → forest, warning → sun, danger → fire, info → water.
Decorative - ComponentTone
<Badge tone="fire">fire</Badge>Semantic - StatusTone
<StatusIndicator variant="danger" label="danger" />Semantic colors
Success, warning, danger, and info are deliberately muted, never neon, and keep the same hue in every theme and material, so meaning never depends on the active appearance.
Success
--fuji-forest
Warning
--fuji-sun
Danger
--fuji-fire
Info
--fuji-water
A note on the old ‘primary’ tone
Fuji UI's native visual language treats default as the main action color. Earlier versions also shipped a primary tone that was a pure alias of default - both resolved to the same token (--fuji-primary aliased --fuji-default) in every theme. primary has since been removed in favor of a single canonical default tone. The default and contained combination still adapts automatically per theme: black on light and warm off-white on dark, in either material. If a distinct accent hue is introduced later, only the token aliases change.
Shadows
Shadows are layered (two stacked box-shadows per level) and soft, never a single flat drop shadow, and grow stronger from control to overlay. Not every element gets a visible shadow; subtle surfaces and ghost buttons intentionally have none.
control
Buttons, inputs, small controls
card
Cards, standard panels
panel
Elevated panels, dropdowns
overlay
Dialogs, drawers, popovers, menus
