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, and this page is available as Markdown at https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md.
  • English
  • ConfigProvider

    Set a shared theme, language and component defaults for an application or a local region.

    Wrap the application to configure it globally, or nest providers to customize one region.

    ConfigureProp
    Built-in text and custom languageslocale, translations
    Primary color, appearance, size and spacingtheme, density
    Shared component propscomponents

    Multilingual

    locale changes built-in text in date panels, empty states and clear actions. Translate business headings, field labels and options in your application.

    Built-in languages

    These translations are included without importing a language pack. The default is Simplified Chinese when locale is not configured.

    Languagelocale
    简体中文 (Simplified Chinese)zh-CN
    繁體中文 (Traditional Chinese)zh-TW
    Englishen-US
    日本語 (Japanese)ja-JP
    한국어 (Korean)ko-KR

    For another language, provide translation resources. A language tag alone does not translate built-in text. Missing entries ultimately fall back to English.

    Switch languages

    Update locale to switch languages. Select a language from the dropdown, then open the date or empty-options control to compare built-in text in all five languages.

    locale.tsx
    import { ConfigProvider, DatePicker, Form, FormField, Select, Space } from '@ifhover/leaf-ui';
    
    import { useState } from 'react';
    
    export function ConfigProviderLocale() {
      const [locale, setLocale] = useState('en-US');
      return (
        <Space direction="vertical" align="stretch">
          <Select
            aria-label="Component language"
            value={locale}
            onChange={setLocale}
            options={[
              { value: 'zh-CN', label: '简体中文' },
              { value: 'zh-TW', label: '繁體中文' },
              { value: 'en-US', label: 'English' },
              { value: 'ja-JP', label: '日本語' },
              { value: 'ko-KR', label: '한국어' },
            ]}
          />
          <ConfigProvider locale={locale}>
            <Form>
              <FormField label="Date">
                <DatePicker />
              </FormField>
              <FormField label="Empty options">
                <Select options={[]} />
              </FormField>
            </Form>
          </ConfigProvider>
        </Space>
      );
    }
    

    Nested regions inherit their parent language unless overridden. direction controls text direction; weekStartsOn sets the first day of the week. Popups inherit these settings too.

    Add your own language

    Copy the complete English JSON, translate it, and pass your imported file through translations. Each key is a language tag. The JSON contains component groups and text only; do not repeat the language tag inside it. Partial resources are supported.

    👽 A small Easter egg: this example uses “Martian” text, a playful style of Chinese internet writing that mixes homophones, lookalike characters, and symbols.

    Missing entries fall back to English. Application content such as field names and confirmation descriptions remains under your control.

    It uses the private-use language tag zh-CN-x-mars, so dates and numbers retain Simplified Chinese regional formatting. This is a demonstration, not a built-in language.

    translations.tsx
    import { Button, ConfigProvider, DatePicker, Form, FormField, Pagination, Select, Space, useConfirm } from '@ifhover/leaf-ui';
    
    import mars from '../../config-provider/zh-CN-x-mars.json';
    
    const translations = { 'zh-CN-x-mars': mars };
    
    function Controls() {
      const { confirm } = useConfirm();
      return (
        <Space direction="vertical" align="stretch">
          <Form>
            <FormField label="Date">
              <DatePicker />
            </FormField>
            <FormField label="Empty options">
              <Select options={[]} />
            </FormField>
          </Form>
          <Pagination total={24} showTotal />
          <Button
            variant="outline"
            onClick={() =>
              void confirm({
                title: 'Continue?',
                children:
                  'Confirm and Cancel use Martian text. Missing translations fall back to English.',
              })
            }
          >
            Open confirmation
          </Button>
        </Space>
      );
    }
    
    export function ConfigProviderTranslations() {
      return (
        <ConfigProvider locale={['zh-CN-x-mars', 'en-US']} translations={translations}>
          <Controls />
        </ConfigProvider>
      );
    }
    

    The imported zh-CN-x-mars.json:

    {
      "common": {
        "confirm": "確萣",
        "cancel": "筭ㄋ"
      },
      "select": {
        "placeholder": "挑①個唄",
        "empty": "暫蒔木洧選項"
      },
      "datePicker": {
        "placeholder": "選個ㄖ剘"
      },
      "pagination": {
        "total": "共 {total} 條數據"
      }
    }
    

    locale={['zh-CN-x-mars', 'en-US']} looks up each missing entry in order, with built-in English as the final fallback. The first tag always controls the current language and regional date and number formatting. A string equals a one-item array; empty arrays are invalid. No implicit zh-CN-x-mars → zh-CN or fr-CA → fr fallback is added.

    Nested translations merge by language and entry. An omitted locale inherits the chain; an explicit value replaces it. Text supplied through component props or components takes precedence. See Translation resources for types, JSON Schema and validation.

    Theme and appearance

    Regional themes

    The theme applies to components and their popups. Usually a primary color or base radius is enough; related styles follow automatically.

    basic.tsx
    import { Button, ConfigProvider, Form, FormField, Input, Select } from '@ifhover/leaf-ui';
    
    export function ConfigProviderBasic() {
      return (
        <ConfigProvider theme={{ primaryColor: '#7654c6', borderRadius: 8 }}>
          <Form onSubmit={(event) => event.preventDefault()}>
            <FormField label="Project name">
              <Input defaultValue="Leaf UI" />
            </FormField>
            <FormField label="Project type">
              <Select
                defaultValue="website"
                options={[
                  { value: 'website', label: 'Website' },
                  { value: 'app', label: 'Application' },
                ]}
              />
            </FormField>
            <Button type="submit">Save settings</Button>
          </Form>
        </ConfigProvider>
      );
    }
    

    Regional density

    density="compact" reduces control sizes and content spacing for information-heavy interfaces. The default is comfortable. Nested regions can choose their own density.

    Comfortable
    Compact
    density.tsx
    import { Button, ConfigProvider, Form, FormField, Input, Select, Space, Text } from '@ifhover/leaf-ui';
    
    export function ConfigProviderDensity() {
      return (
        <Space direction="vertical" align="stretch" size="lg">
          {(['comfortable', 'compact'] as const).map((density) => (
            <ConfigProvider key={density} density={density}>
              <Space direction="vertical" align="stretch">
                <Text tone="muted">{density === 'compact' ? 'Compact' : 'Comfortable'}</Text>
                <Form>
                  <FormField label="Project name">
                    <Input defaultValue="Leaf UI" />
                  </FormField>
                  <FormField label="Owner">
                    <Select
                      options={[
                        { value: 'lin', label: 'Lin' },
                        { value: 'alex', label: 'Alex' },
                      ]}
                      defaultValue="lin"
                    />
                  </FormField>
                  <Button type="reset" variant="outline">
                    Reset
                  </Button>
                </Form>
              </Space>
            </ConfigProvider>
          ))}
        </Space>
      );
    }
    

    Base height

    Set theme.controlHeight to change the size baseline. Small and large controls derive their heights automatically, so individual buttons and inputs stay consistent.

    Small
    Default
    Large
    sizes.tsx
    import { Button, ConfigProvider, Form, FormField, Slider, Space, Text } from '@ifhover/leaf-ui';
    
    import { useState } from 'react';
    
    export function ConfigProviderSizes() {
      const [height, setHeight] = useState(36);
      return (
        <Space direction="vertical" align="stretch" size="lg">
          <Form>
            <FormField label={`Base height: ${height}px`}>
              <Slider min={28} max={44} value={height} onChange={setHeight} showValue={false} />
            </FormField>
          </Form>
          <ConfigProvider theme={{ controlHeight: height }}>
            <Space wrap align="end" size="lg">
              {(
                [
                  ['sm', 'Small'],
                  ['md', 'Default'],
                  ['lg', 'Large'],
                ] as const
              ).map(([size, label]) => (
                <Space key={size} direction="vertical" size="sm">
                  <Text tone="muted">{label}</Text>
                  <Button size={size} variant="outline">
                    Button
                  </Button>
                </Space>
              ))}
            </Space>
          </ConfigProvider>
        </Space>
      );
    }
    

    For further customization, see Theming. theme.components changes local component styles; components below sets default component props. For server rendering, see SSR.

    Component defaults

    Set common props once instead of repeating them on every component. Use components to share button styles, input hints and modal closing behavior. Change the configuration once when your conventions change.

    Configure the app root to apply defaults throughout the app, or wrap a region to keep them local. Individual components can still override them with their own props.

    Consistent form defaults

    This example shares placeholders, clear buttons and button styles. The end date and Save button override the shared defaults.

    defaults.tsx
    import { Button, ConfigProvider, DatePicker, Form, FormField, Input, Space } from '@ifhover/leaf-ui';
    
    export function ConfigProviderDefaults() {
      return (
        <ConfigProvider
          components={{
            Button: { variant: 'outline' },
            Input: { placeholder: 'Enter a project name', allowClear: true },
            DatePicker: { placeholder: 'Choose a project start date', allowClear: true },
          }}
        >
          <Form onSubmit={(event) => event.preventDefault()}>
            <FormField label="Project name">
              <Input />
            </FormField>
            <FormField label="Start date">
              <DatePicker />
            </FormField>
            <FormField label="End date">
              <DatePicker placeholder="Instance override: choose an end date" />
            </FormField>
            <Space wrap>
              <Button type="reset">Reset</Button>
              <Button type="submit" variant="solid">
                Save (instance override)
              </Button>
            </Space>
          </Form>
        </ConfigProvider>
      );
    }
    

    Prevent accidental dismissal from mask clicks

    Keep an accidental mask click from interrupting an edit: set Modal: { maskClosable: false } once for every Modal in the region. The close button and Esc still work.

    modal-defaults.tsx
    import { Button, ConfigProvider, Modal, Paragraph } from '@ifhover/leaf-ui';
    
    import { useState } from 'react';
    
    export function ConfigProviderModalDefaults() {
      const [open, setOpen] = useState(false);
    
      return (
        <ConfigProvider components={{ Modal: { maskClosable: false } }}>
          <Button onClick={() => setOpen(true)}>Open modal</Button>
          <Modal open={open} title="Mask clicks keep this open" onClose={() => setOpen(false)}>
            <Paragraph>
              Try clicking outside the modal. It stays open. The close button, footer actions and Esc
              still close it.
            </Paragraph>
          </Modal>
        </ConfigProvider>
      );
    }
    

    Inheritance and overrides

    Shared defaults leave room for local changes: instance props > inner configuration > outer configuration > built-in defaults.

    Outer scope
    Inner size override
    Instance override
    inheritance.tsx
    import { Button, ConfigProvider, Flex, Space, Text } from '@ifhover/leaf-ui';
    
    export function ConfigProviderInheritance() {
      return (
        <ConfigProvider components={{ Button: { variant: 'outline', size: 'sm' } }}>
          <Space direction="vertical" align="stretch">
            <Flex justify="space-between" align="center" gap="md">
              <Text tone="muted">Outer scope</Text>
              <Button>Small · Outline</Button>
            </Flex>
            <ConfigProvider components={{ Button: { size: 'lg' } }}>
              <Space direction="vertical" align="stretch">
                <Flex justify="space-between" align="center" gap="md">
                  <Text tone="muted">Inner size override</Text>
                  <Button>Large · Outline</Button>
                </Flex>
                <Flex justify="space-between" align="center" gap="md">
                  <Text tone="muted">Instance override</Text>
                  <Button size="md" variant="solid">
                    Default · Solid
                  </Button>
                </Flex>
              </Space>
            </ConfigProvider>
          </Space>
        </ConfigProvider>
      );
    }
    

    Clearing inherited defaults

    Set a component entry to null to restore its built-in defaults locally, for example components={{ Input: null }}.

    reset.tsx
    import { ConfigProvider, Form, FormField, Input, type LeafComponentDefaults } from '@ifhover/leaf-ui';
    
    const defaults = { Input: { readOnly: true } } satisfies LeafComponentDefaults;
    
    export function ConfigProviderReset() {
      return (
        <ConfigProvider components={defaults}>
          <Form>
            <FormField label="Inherited defaults">
              <Input defaultValue="This input is read-only" />
            </FormField>
            <ConfigProvider components={{ Input: null }}>
              <FormField label="Clear defaults in this region">
                <Input defaultValue="Try editing this text" />
              </FormField>
            </ConfigProvider>
          </Form>
        </ConfigProvider>
      );
    }
    

    API

    ConfigProvider API

    PropertyTypeDefaultDescription
    localeLeafLocale | readonly LeafLocale[]'zh-CN'Current language and per-entry fallback order; inherited when omitted
    translationsReadonly<Record<string, LeafTranslation>>—JSON resources indexed by language tag; nested entries merge
    themeLeafTheme—Regional settings; omitted fields inherit
    direction'ltr' | 'rtl'—Text and interaction direction.
    weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6—First day of the week; 0 is Sunday and 1 is Monday.
    getPopupContainer() => Element | DocumentFragment—Return a popup container, including a ShadowRoot.
    maskBlurbooleantrueEnable mask blur for Modal, Drawer and Modal-based overlays such as confirmations and command palettes. Disable to reduce rendering cost; nested providers inherit it.
    density'comfortable' | 'compact''comfortable'Inherited controls, forms, menus, lists and overlay spacing; explicit sizes override the preset.
    componentsLeafComponentDefaults—Regional component defaults, inherited by component and prop.

    Native div props, className and style apply to the region wrapper. maskBlur={false} disables backdrop blur while preserving the translucent mask; this is independent of theme.motion.

    LeafTheme

    Common theme options. Unspecified fields inherit from the outer region.

    PropertyTypeDefaultDescription
    primaryColorstring'#20834a'Primary color with derived interaction states; dark appearance defaults to a lighter green
    borderRadiusnumber | string10Base radius; small / medium / large radii use × 0.6 / 1.2 / 1.6
    controlHeightnumber | string36Base height; small / large heights use − / + 6px
    fontSizenumber | string14Base font; small font − 1px, large font + 2px
    fontFamilystringSystem sans-serifFont family
    appearance'light' | 'dark''light'Light or dark; inherits explicit ancestor settings
    motionbooleantrueEnable interaction motion in this region; reduced-motion preferences take precedence and portals inherit it.
    tokensLeafThemeTokens—Optional advanced overrides
    spacingnumber—Base spacing; other spacing values are derived.
    lineHeightnumber—Body line height.
    headingWeightnumber—Weight of Typography document headings; component titles use tokens.fontWeight.
    elevation'none' | 'soft' | 'medium'—Overall shadow strength.
    breakpointsPartial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl', number>>—Responsive thresholds used by useBreakpoint.
    componentsRecord<string, LeafComponentTokens>—Override local styles by component name.

    Types and complete reference

    Import types when creating reusable configuration:

    import type { ConfigProviderProps, LeafComponentDefaults, LeafTheme } from '@ifhover/leaf-ui';