Skip to content

Component API

Fuji's components share one set of conventions, so learning one component teaches you most of the rest. This page covers the shared props, the compound-component pattern, and the three layers of customization.

Shared props

Every applicable component accepts the same three props, with the same defaults. tone below is for purely decorative color choices (Button, Badge, Icon); components whose value carries meaning (Alert, Toast, Result, Progress) use a separate variant prop instead, with values default · success · warning · danger · info - see Theming for the full distinction.

PropValuesDefault
sizesm · md · lgmd
tonedefault · earth · fire · water · forest · sundefault
appearancecontained · bordered · dashed · ghostcontained

appearance, not type

Visual style is controlled by appearance specifically so the native HTML type attribute stays free for its real purpose:

tsx
<Button type="submit" tone="forest" appearance="contained">
  Approve
</Button>

What every applicable component supports

  • Native HTML props and ref forwarding
  • className on the root, and classNames for named internal slots where more than one visual part exists
  • A controlled and uncontrolled pair with a change callback, named for what the component holds: value/defaultValue for inputs, open/defaultOpen with onOpenChange for overlays, and specific names elsewhere (Pagination page, Stepper activeStep). Each component page documents its own
  • Disabled, loading, invalid, read-only, and selected states
  • Visible focus (:focus-visible), accessible labels, and full keyboard operability

Compound components over prop explosion

Components with multiple visual parts (Card, Dialog, Table, Select) expose those parts as compound sub-components rather than a single component with a dozen slot props:

tsx
<Card>
  <Card.Header>
    <Card.Title>Plan</Card.Title>
  </Card.Header>
  <Card.Content>...</Card.Content>
</Card>

The default and contained combination adapts automatically per theme (black on light, warm off-white on dark, frosted high contrast on glass) through semantic tokens; components never branch on the active theme in JavaScript.

Customization

Three layers, in order of how often you reach for them.

1. className

Every component accepts className on its root, merged with tailwind-merge so conflicting utilities (for example your own rounded-full overriding the default control radius) resolve predictably instead of duplicating.

tsx
<Button className="w-full rounded-full">Continue</Button>

2. classNames (named slots)

Components with more than one visually distinct part expose those parts directly as compound sub-components you can pass className to individually, rather than a single flat classNames map; this keeps the JSX legible for deeply nested overlays.

3. Tokens

For changes that should apply everywhere (a different accent, a tighter shadow), override the --fuji-* custom properties in your own CSS rather than overriding classes per instance. Every component reads the same variables, so a token change is a one-place edit that cascades everywhere.

css
/* your app stylesheet, loaded after @fujiui/react/styles.css */
:root {
  --fuji-default: #1c1b19;
  --fuji-radius-control: 10px;
}