> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/en/guide/theming.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt.

# Theming

Set colors, corner radii and dark mode through ConfigProvider's `theme`. A few settings are usually enough; related styles update automatically.

## Change colors and corners

Wrap your application in ConfigProvider. This example uses a purple primary color and an 8px base radius:


Save changes

basic.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/theming/basic.tsx"
import { Button, ConfigProvider } from '@ifhover/leaf-ui';

export function ThemeBasic() {
  return (
    <ConfigProvider theme={{ primaryColor: '#7654c6', borderRadius: 8 }}>
      <Button>Save changes</Button>
    </ConfigProvider>
  );
}
```

Expand code

Replace Button with your application content. Buttons, fields, selectors and popups share the theme. Hover, pressed and focus colors derive automatically.

`borderRadius` sets the base radius. Cards, dialogs and other surfaces derive radii for their own level, so you do not need to configure each component. Numbers represent pixels; CSS lengths such as `'0.5rem'` also work.

### Common settings

These fields all belong inside `theme`. Set only what you want to change.

| Setting         | Example               | Purpose                                                                |
| --------------- | --------------------- | ---------------------------------------------------------------------- |
| `primaryColor`  | `'#7654c6'`           | Set the primary color and derive related interaction colors.           |
| `borderRadius`  | `8`                   | Set the base radius; use `0` for square corners.                       |
| `appearance`    | `'light'` / `'dark'`  | Choose light or dark appearance.                                       |
| `controlHeight` | `40`                  | Set the base single-line control height; small and large sizes follow. |
| `fontSize`      | `14`                  | Set the base component font size.                                      |
| `fontFamily`    | `'Inter, sans-serif'` | Set the font family; your application loads the font files.            |
| `motion`        | `false`               | Disable regional animations while keeping interactions available.      |

Unspecified fields inherit the outer configuration. Defaults are light appearance, a 10px base radius, 36px base control height and 14px font size.

See [LeafTheme](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md#leaftheme) for all theme fields. For individual text colors, backgrounds or sizes, use [LeafThemeTokens](https://ifhover.github.io/leaf-ui/v/0.6.0/en/api/theme-tokens.md#leafthemetokens).

## Use dark mode

Set `appearance: 'dark'`. Use `'light'` to switch back:

```tsx
<ConfigProvider theme={{ appearance: 'dark' }}>
  <App />
</ConfigProvider>
```

Component text, backgrounds and borders change together. An explicit `primaryColor` keeps its value; otherwise, the appearance supplies its default primary color.

ConfigProvider styles the components in its region. It does not add a background to the page's `body`. To update your own page backgrounds and text, use the [CSS variables](#use-the-theme-in-application-css) below.

### Add an appearance switch

Theme settings are ordinary React props, so state can update them. Toggle the switch below to change the card, button and text together:


Dark modeSave changes

appearance.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/theming/appearance.tsx"
import { Button, Card, ConfigProvider, Flex, Switch } from '@ifhover/leaf-ui';

import { useState } from 'react';

export function ThemeAppearance() {
  const [dark, setDark] = useState(false);

  return (
    <ConfigProvider theme={{ appearance: dark ? 'dark' : 'light' }}>
      <Card>
        <Flex direction="column" gap="md" align="start">
          <Switch checked={dark} onChange={(event) => setDark(event.target.checked)}>
            Dark mode
          </Switch>
          <Button>Save changes</Button>
        </Flex>
      </Card>
    </ConfigProvider>
  );
}
```

Expand code

### Follow the system

Use `useSystemAppearance` and pass its result to `theme.appearance` to follow the operating system:

```tsx
import { ConfigProvider, useSystemAppearance } from '@ifhover/leaf-ui';

export function AppTheme() {
  const appearance = useSystemAppearance('light');

  return (
    <ConfigProvider theme={{ appearance }}>
      <App />
    </ConfigProvider>
  );
}
```

The `'light'` argument is the initial appearance. After mounting, the hook reads and watches system preferences. Your application stores manual choices and decides when to keep following the system.

## Theme one region

Nest another ConfigProvider to theme a specific area. The inner provider overrides only the supplied fields and inherits the rest:


Global blue

Local purple

scoped.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/theming/scoped.tsx"
import { Button, ConfigProvider, Flex } from '@ifhover/leaf-ui';

export function ThemeScoped() {
  return (
    <ConfigProvider theme={{ primaryColor: '#1677ff', borderRadius: 8 }}>
      <Flex direction="column" gap="md" align="start">
        <Button>Global blue</Button>
        <ConfigProvider theme={{ primaryColor: '#7654c6' }}>
          <Button>Local purple</Button>
        </ConfigProvider>
      </Flex>
    </ConfigProvider>
  );
}
```

Expand code

Both buttons use an 8px base radius. The inner provider changes only the primary color to purple. Select popups, Modal, and feedback created with `useConfirm` or `useMessage` also use their calling region's theme.

## Adjust control size and density

For one control, prefer its `size="sm"` or `size="lg"` prop. To make an entire region more compact, set ConfigProvider's `density`:

```tsx
<ConfigProvider density="compact">
  <App />
</ConfigProvider>
```

`density` is a sibling of `theme`. It defaults to `'comfortable'`. The `'compact'` preset tightens control, form and popup spacing and changes the base control height from 36px to 30px without reducing text size.

Set `theme.controlHeight` when you need an explicit height; it overrides the density preset. For example, `controlHeight: 40` produces 34px / 40px / 46px controls. See [ConfigProvider](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md#base-height) for a size comparison.

## Advanced customization

Use the settings below when your design needs more specific overrides. For colors, corners and appearance, the basic settings above are sufficient.

### Override individual colors or sizes

Use `theme.tokens` for specific styles beyond the basic settings. This example adjusts the success color, large radius and animation duration:

```tsx
import type { LeafTheme } from '@ifhover/leaf-ui';

const theme = {
  primaryColor: '#7654c6',
  borderRadius: 8,
  tokens: {
    successColor: '#20834a',
    borderRadiusLg: 18,
    motionDuration: 160,
  },
} satisfies LeafTheme;
```

Pass this object to `<ConfigProvider theme={theme}>`. Here, `borderRadiusLg` overrides the derived large radius, and numeric `motionDuration` values are milliseconds. See [LeafThemeTokens](https://ifhover.github.io/leaf-ui/v/0.6.0/en/api/theme-tokens.md#leafthemetokens) for the complete reference.

For a very light primary color, use `tokens.onPrimaryColor` to set the text color on solid primary buttons. Check readability in normal, hovered and disabled states after changing your palette. `motion: false` disables regional animations; system reduced-motion preferences always take precedence.

### Style one component type

`theme.components` assigns styles by component name. For example, use 4px button corners and change card padding:

```tsx
<ConfigProvider theme={{
  components: {
    Button: { borderRadius: 4 },
    Card: { padding: 24 },
  },
}}>
  <App />
</ConfigProvider>
```

See [LeafComponentTokens](https://ifhover.github.io/leaf-ui/v/0.6.0/en/api/theme-tokens.md#leafcomponenttokens) for style fields, and each component's documentation for the fields it supports.

`theme.components` changes styles. To set default button `size`, `variant` or other component props, use ConfigProvider's separate `components` prop; see [Component defaults](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md#component-defaults).

### Use the theme in application CSS

ConfigProvider exposes `--leaf-*` CSS variables within its region. Your own content can read them to follow color and appearance changes:

```tsx
<ConfigProvider theme={{ appearance: 'dark' }}>
  <section className="app-panel">Application content</section>
</ConfigProvider>
```

```css
.app-panel {
  padding: 16px;
  color: var(--leaf-color-text);
  background: var(--leaf-color-surface);
  border: 1px solid var(--leaf-color-border);
  border-radius: var(--leaf-radius);
}
```

| Common variable                                       | Purpose                             |
| ----------------------------------------------------- | ----------------------------------- |
| `--leaf-color-primary`                                | Current primary color.              |
| `--leaf-color-on-primary`                             | Text on a solid primary background. |
| `--leaf-color-text` / `--leaf-color-text-muted`       | Primary and secondary text.         |
| `--leaf-color-surface` / `--leaf-color-surface-muted` | Content and supporting backgrounds. |
| `--leaf-color-border`                                 | Border color.                       |
| `--leaf-radius`                                       | Base radius.                        |

Configure Leaf UI component themes through ConfigProvider and read the results from application CSS. Changing a single base CSS variable does not regenerate the full set of interaction colors.

For Tailwind CSS, import the package configuration to reuse the theme through utilities such as `bg-leaf-surface` and `text-leaf-primary`. See [Tailwind CSS](https://ifhover.github.io/leaf-ui/v/0.6.0/en/guide/tailwindcss.md) for Tailwind 3 / 4 setup.

## Server rendering

Use the same appearance for the server and the client's initial render. To remember a user's choice, read a cookie on the server and supply that initial value. System appearance updates after mounting.

Prefer concrete HEX, RGB or HSL colors. A color such as `var(--brand-color)` resolves after mounting in the browser and cannot guarantee matching derived colors in the server's first frame.

See [Installation & quick start](https://ifhover.github.io/leaf-ui/v/0.6.0/en/guide/getting-started.md) for setup, [server-side rendering](https://ifhover.github.io/leaf-ui/v/0.6.0/en/guide/ssr.md) for frameworks such as Next.js, and [Browser compatibility](https://ifhover.github.io/leaf-ui/v/0.6.0/en/guide/compatibility.md) for support targets.
