ConfigProvider

free

ConfigProvider scopes shared UI defaults for product components beneath it.

Preview
Dark
import Button from '@/components/ui/Button';
import ConfigProvider, {
  useConfig,
} from '@/components/ui/ConfigProvider';
import Form from '@/components/ui/Form';
import Input from '@/components/ui/Input';

export default function UsageDemo() {
  const config = useConfig();

  return (
    <div className="flex flex-col max-w-125 w-full mx-auto gap-4 p-4">
      <ConfigProvider
        value={{
          ...config,
          controlSize: 'sm',
        }}
      >
        <div>
          <div className="text-base font-semibold text-foreground">
            Compact controls
          </div>
          <p className="text-muted-foreground">
            These controls are smaller than the default size.
          </p>
        </div>
        <Form onSubmit={(event) => event.preventDefault()}>
          <Form.Field
            label="Role"
            htmlFor="config-provider-usage-role"
          >
            <Input
              id="config-provider-usage-role"
              defaultValue="Editor"
            />
          </Form.Field>
          <Form.Field
            label="Team"
            htmlFor="config-provider-usage-team"
          >
            <Input
              id="config-provider-usage-team"
              defaultValue="Operations"
            />
          </Form.Field>
          <div className="flex justify-end gap-2">
            <Button type="button">Cancel</Button>
            <Button type="submit" variant="solid">Save invite</Button>
          </div>
        </Form>
      </ConfigProvider>
    </div>
  );
}

Installation

Add this component with the NateUI CLI.

npx nateui@latest add ConfigProvider

Examples

Control Size

controlSize sets the inherited size for descendant controls that read the provider config.

Preview
Dark
import { useState } from 'react';
import Button from '@/components/ui/Button';
import ConfigProvider, {
  useConfig,
} from '@/components/ui/ConfigProvider';
import Form from '@/components/ui/Form';
import Input from '@/components/ui/Input';
import Segment from '@/components/ui/Segment';
import { PiMagnifyingGlass } from 'react-icons/pi'

const sizes = [
  { label: 'Compact', value: 'sm' },
  { label: 'Default', value: 'md' },
  { label: 'Roomy', value: 'lg' },
] as const;

type ControlSize = (typeof sizes)[number]['value'];

export default function ControlSizeDemo() {
  const [size, setSize] = useState<ControlSize>('md');
  const config = useConfig();
  const currentSize = sizes.find((item) => item.value === size);

  return (
    <div className="flex min-h-88 w-full items-center justify-center p-4">
      <div className="w-full max-w-125">
        <div className="flex flex-col gap-4">
          <Segment
            value={size}
            onChange={(nextSize) => setSize(nextSize as ControlSize)}
          >
            {sizes.map((item) => (
              <Segment.Item key={item.value} value={item.value}>
                {item.label}
              </Segment.Item>
            ))}
          </Segment>
        </div>
        <div className="py-4">
          <ConfigProvider
            value={{
              ...config,
              controlSize: size,
            }}
          >
            <Form onSubmit={(event) => event.preventDefault()}>
              <Form.Field
                label="Search"
                htmlFor="config-provider-size-search"
              >
                <Input
                  id="config-provider-size-search"
                  defaultValue="Priority invoices"
                  prefix={<PiMagnifyingGlass />}
                />
              </Form.Field>
              <Form.Field
                label="Owner"
                htmlFor="config-provider-size-owner"
              >
                <Input
                  id="config-provider-size-owner"
                  defaultValue="Mira Chen"
                />
              </Form.Field>
              <Form.Field
                label="Batch"
                htmlFor="config-provider-size-batch"
              >
                <Input
                  id="config-provider-size-batch"
                  defaultValue="Q3 approvals"
                />
              </Form.Field>
              <Button type="submit" variant="solid" block>
                Assign batch
              </Button>
            </Form>
          </ConfigProvider>
        </div>
      </div>
    </div>
  );
}

Direction

direction switches descendant controls between left-to-right and right-to-left layout.

Preview
Dark
import ConfigProvider, {
  useConfig,
} from '@/components/ui/ConfigProvider';
import Input from '@/components/ui/Input';
import Segment from '@/components/ui/Segment';
import { PiMagnifyingGlass } from 'react-icons/pi'

export default function DirectionDemo() {
  const config = useConfig();

  return (
    <div className="flex min-h-80 w-full items-center justify-center p-4">
      <ConfigProvider
        value={{
          ...config,
          direction: 'rtl',
        }}
      >
        <div
          dir="rtl"
          className="w-full max-w-xl overflow-hidden rounded-card border border-border bg-card"
        >
          <div className="border-b border-border px-4 py-3">
            <div className="font-medium text-foreground">إعدادات الفريق</div>
            <p className="text-sm text-muted-foreground">
              اتجاه العناصر محدد داخل نطاق هذا المزود.
            </p>
          </div>
          <div className="grid gap-4 p-4">
            <Segment defaultValue="billing">
              <Segment.Item value="overview">نظرة عامة</Segment.Item>
              <Segment.Item value="billing">الفواتير</Segment.Item>
              <Segment.Item value="users">المستخدمون</Segment.Item>
            </Segment>
            <Input
              aria-label="البحث داخل نطاق من اليمين إلى اليسار"
              defaultValue="الفواتير المفتوحة"
              prefix={<PiMagnifyingGlass />}
              suffix="بحث"
            />
            <div className="grid gap-3 rounded-control bg-muted p-3">
              <div className="flex items-center justify-between gap-4">
                <span className="font-medium text-foreground">
                  فاتورة العملاء
                </span>
                <span className="text-sm text-muted-foreground">
                  ١٢ عنصر
                </span>
              </div>
              <div className="flex items-center justify-between gap-4 text-sm">
                <span className="text-muted-foreground">آخر تحديث</span>
                <span className="font-medium text-foreground">
                  قبل ٣ دقائق
                </span>
              </div>
            </div>
          </div>
        </div>
      </ConfigProvider>
    </div>
  );
}

Locale

locale supplies locale keys to components that render localized labels.

Preview
Dark
import 'dayjs/locale/fr';
import Calendar from '@/components/ui/Calendar';
import ConfigProvider, {
  useConfig,
} from '@/components/ui/ConfigProvider';

export default function LocaleDemo() {
  const config = useConfig();

  return (
    <div className="flex w-full items-center justify-center p-4">
      <ConfigProvider
        value={{
          ...config,
          locale: 'fr',
        }}
      >
        <div className="grid gap-4">
          <div>
            <div className="font-semibold text-foreground">French locale</div>
            <p className="text-muted-foreground">
              Calendar labels read from the provider locale.
            </p>
          </div>
          <Calendar
            defaultMonth={new Date(2026, 6, 1)}
            value={new Date(2026, 6, 14)}
          />
        </div>
      </ConfigProvider>
    </div>
  );
}

Slot Class Names

classNames applies scoped slot overrides to components rendered inside the provider.

Preview
Dark
import Tag from '@/components/ui/Tag';
import Card from '@/components/ui/Card';
import ConfigProvider, {
  useConfig,
} from '@/components/ui/ConfigProvider';
import Input from '@/components/ui/Input';

export default function SlotClassNamesDemo() {
  const config = useConfig();

  return (
    <div className="flex min-h-80 w-full items-center justify-center p-4">
      <ConfigProvider
        value={{
          ...config,
          classNames: {
            ...config.classNames,
            card: {
              ...config.classNames?.card,
              root: 'bg-primary-soft p-1',
              header: 'bg-primary-soft border-0',
              footer: 'border-0 pb-1 text-primary',
              body: 'bg-card rounded-card',
            },
            tag: {
              ...config.classNames?.tag,
              root: 'rounded-full text-primary bg-card',
            },
          },
        }}
      >
        <Card
          className="w-full max-w-sm"
          footer={{ 
            content: 'Slot-tuned card',
            className: 'text-center font-medium',
          }}
        >
          <div className="grid gap-4">
            <div>
              <div className="text-base font-semibold">Senior Product Manager</div>
              <span className="text-muted-foreground">$120,000 ~ $140,000</span>
            </div>
            <div className="flex gap-2">
              <Tag>Full-time</Tag>
              <Tag>Remote</Tag>
            </div>
          </div>
          
        </Card>
      </ConfigProvider>
    </div>
  );
}

API

ConfigProvider is the exported React context provider for NateUI component configuration. It expects a full config value; spread the current useConfig() value or defaultConfig when changing one field.

PropDescriptionTypeDefault
valueComplete configuration object used by descendant UI components.ConfigRequired
childrenSubtree that receives the supplied configuration.ReactNode-

Exports

ExportDescription
ConfigProviderDefault provider component.
useConfigReads the nearest provider value, falling back to defaultConfig.
defaultConfigBaseline config: light mode, English locale, medium controls, left-to-right direction, and no slot overrides.
ConfigContextRaw React context for advanced integrations.
ConfigConsumerContext consumer export for non-hook consumers.

Types

type Config = {
  mode: 'light' | 'dark';
  locale: string;
  controlSize: TypeAttributes.ControlSize;
  direction: TypeAttributes.Direction;
  classNames?: ConfigClassNames;
};
 
type SlotClassNames<TSlot extends string> =
  Partial<Record<TSlot, string>>;
 
declare namespace TypeAttributes {
  type Shape = 'round' | 'circle' | 'none';
  type Status = 'success' | 'warning' | 'danger' | 'info';
  type FormLayout = 'horizontal' | 'vertical' | 'inline';
  type ControlSize = 'lg' | 'md' | 'sm';
  type Direction = 'ltr' | 'rtl';
  type Placement =
    | 'top'
    | 'right'
    | 'bottom'
    | 'left'
    | 'top-start'
    | 'top-end'
    | 'right-start'
    | 'right-end'
    | 'bottom-start'
    | 'bottom-end'
    | 'left-start'
    | 'left-end';
}
 
type ActionBarConfigClassNames = SlotClassNames<'root' | 'content'>;
 
type AlertConfigClassNames = SlotClassNames<
  'root' | 'content' | 'icon' | 'title' | 'description' | 'close'
>;
 
type AvatarConfigClassNames = SlotClassNames<
  'root' | 'image' | 'icon' | 'fallback' | 'group' | 'overflow'
>;
 
type BadgeConfigClassNames = SlotClassNames<'root' | 'indicator'>;
 
type ButtonConfigClassNames = SlotClassNames<
  'root' | 'label' | 'icon' | 'spinner'
>;
 
type BreadcrumbConfigClassNames = SlotClassNames<
  | 'root'
  | 'list'
  | 'item'
  | 'link'
  | 'page'
  | 'separator'
  | 'ellipsis'
  | 'icon'
>;
 
type CalendarConfigClassNames = SlotClassNames<
  | 'root'
  | 'view'
  | 'header'
  | 'headerLabel'
  | 'previousTrigger'
  | 'nextTrigger'
  | 'table'
  | 'weekday'
  | 'week'
  | 'cell'
  | 'day'
  | 'monthGrid'
  | 'monthCell'
  | 'yearGrid'
  | 'yearCell'
>;
 
type RangeCalendarConfigClassNames = CalendarConfigClassNames;
 
type CardConfigClassNames = SlotClassNames<
  'root' | 'header' | 'headerTitle' | 'headerExtra' | 'body' | 'footer'
>;
 
type CarouselConfigClassNames = SlotClassNames<
  'root' | 'viewport' | 'content' | 'item' | 'previousTrigger' | 'nextTrigger'
>;
 
type CheckboxConfigClassNames = SlotClassNames<
  'root' | 'wrapper' | 'control' | 'indicator' | 'label' | 'group'
>;
 
type CollapsibleConfigClassNames = SlotClassNames<
  'root' | 'trigger' | 'triggerLabel' | 'indicator' | 'content'
>;
 
type DatePickerConfigClassNames = SlotClassNames<
  'trigger' | 'clearButton' | 'panel' | 'calendar' | 'timePanel' | 'action'
>;
 
type DialogConfigClassNames = SlotClassNames<
  'overlay' | 'wrapper' | 'content' | 'close'
>;
 
type DrawerConfigClassNames = SlotClassNames<
  | 'overlay'
  | 'wrapper'
  | 'content'
  | 'header'
  | 'title'
  | 'close'
  | 'handle'
  | 'body'
  | 'footer'
>;
 
type DropdownConfigClassNames = SlotClassNames<
  | 'trigger'
  | 'triggerLabel'
  | 'triggerIndicator'
  | 'contentWrapper'
  | 'content'
  | 'item'
  | 'itemLabel'
  | 'itemIndicator'
  | 'label'
  | 'separator'
  | 'customItem'
  | 'subTrigger'
  | 'subContent'
  | 'subIndicator'
  | 'contextArea'
>;
 
type FormConfigClassNames = SlotClassNames<'root'>;
 
type FormScopeConfigClassNames = SlotClassNames<'root'>;
 
type FormFieldConfigClassNames = SlotClassNames<
  'root' | 'label' | 'asterisk' | 'control' | 'message'
>;
 
type InputConfigClassNames = SlotClassNames<
  'root' | 'control' | 'prefix' | 'suffix'
>;
 
type InputGroupConfigClassNames = SlotClassNames<'root' | 'addon'>;
 
type MenuConfigClassNames = SlotClassNames<
  | 'root'
  | 'group'
  | 'groupLabel'
  | 'groupList'
  | 'item'
  | 'itemIndicator'
  | 'collapse'
  | 'collapseTrigger'
  | 'collapseLabel'
  | 'collapseIndicator'
  | 'collapseContent'
>;
 
type MenuItemConfigClassNames = SlotClassNames<'root' | 'indicator'>;
 
type MultiValueInputConfigClassNames = SlotClassNames<
  | 'root'
  | 'tagList'
  | 'tag'
  | 'tagLabel'
  | 'tagRemove'
  | 'overflowTrigger'
  | 'overflowContent'
  | 'input'
>;
 
type NotificationConfigClassNames = SlotClassNames<
  'root' | 'content' | 'icon' | 'title' | 'description' | 'close'
>;
 
type PaginationConfigClassNames = SlotClassNames<
  | 'root'
  | 'total'
  | 'list'
  | 'item'
  | 'ellipsis'
  | 'previousTrigger'
  | 'nextTrigger'
>;
 
type PopoverConfigClassNames = SlotClassNames<
  'trigger' | 'content' | 'body'
>;
 
type ProgressConfigClassNames = SlotClassNames<
  'root' | 'track' | 'trail' | 'indicator' | 'info'
>;
 
type RateConfigClassNames = SlotClassNames<
  'root' | 'item' | 'icon' | 'label'
>;
 
type RadioConfigClassNames = SlotClassNames<
  'root' | 'wrapper' | 'control' | 'indicator' | 'label' | 'group'
>;
 
type ResizableConfigClassNames = SlotClassNames<
  | 'root'
  | 'handleWrapper'
  | 'top'
  | 'right'
  | 'bottom'
  | 'left'
  | 'topRight'
  | 'bottomRight'
  | 'bottomLeft'
  | 'topLeft'
>;
 
type ScrollConfigClassNames = SlotClassNames<
  'root' | 'viewport' | 'content' | 'scrollbar' | 'thumb' | 'corner' | 'flexRoot'
>;
 
type SegmentConfigClassNames = SlotClassNames<
  'root' | 'item' | 'indicator'
>;
 
type SelectConfigClassNames = SlotClassNames<
  | 'root'
  | 'control'
  | 'trigger'
  | 'value'
  | 'placeholder'
  | 'indicator'
  | 'spinner'
  | 'clearButton'
  | 'menu'
  | 'menuContent'
  | 'filter'
  | 'filterInput'
  | 'group'
  | 'groupLabel'
  | 'item'
  | 'itemText'
  | 'itemIndicator'
  | 'message'
  | 'tag'
  | 'tagRemove'
  | 'multiInput'
>;
 
type SkeletonConfigClassNames = SlotClassNames<'root'>;
 
type SliderConfigClassNames = SlotClassNames<
  'root' | 'trackWrapper' | 'track' | 'range' | 'thumb' | 'tooltip' | 'mark' | 'markLabel'
>;
 
type SpinnerConfigClassNames = SlotClassNames<
  'root' | 'track' | 'indicator'
>;
 
type StepsConfigClassNames = SlotClassNames<
  | 'root'
  | 'item'
  | 'trigger'
  | 'icon'
  | 'content'
  | 'title'
  | 'description'
  | 'connector'
>;
 
type SwitcherConfigClassNames = SlotClassNames<
  'root' | 'control' | 'thumb' | 'spinner' | 'content'
>;
 
type TableConfigClassNames = SlotClassNames<
  | 'root'
  | 'overflow'
  | 'border'
  | 'head'
  | 'body'
  | 'foot'
  | 'row'
  | 'headerCell'
  | 'cell'
  | 'sorter'
  | 'sorterIcon'
>;
 
type TabsConfigClassNames = SlotClassNames<
  'root' | 'list' | 'trigger' | 'icon' | 'indicator' | 'content'
>;
 
type TagConfigClassNames = SlotClassNames<
  'root' | 'label' | 'prefix' | 'suffix'
>;
 
type TimeInputConfigClassNames = SlotClassNames<
  | 'root'
  | 'wrapper'
  | 'field'
  | 'separator'
  | 'period'
  | 'clearButton'
  | 'prefix'
  | 'suffix'
>;
 
type TimelineConfigClassNames = SlotClassNames<
  | 'root'
  | 'item'
  | 'wrapper'
  | 'media'
  | 'mediaContent'
  | 'mediaDot'
  | 'connector'
  | 'content'
>;
 
type TooltipConfigClassNames = SlotClassNames<
  'trigger' | 'content' | 'label'
>;
 
type UploadConfigClassNames = SlotClassNames<
  | 'root'
  | 'input'
  | 'trigger'
  | 'tip'
  | 'list'
  | 'item'
  | 'itemWrapper'
  | 'thumbnail'
  | 'fileIcon'
  | 'fileImage'
  | 'fileInfo'
  | 'fileName'
  | 'fileSize'
  | 'removeButton'
>;
 
type ConfigClassNames = Partial<{
  actionBar: ActionBarConfigClassNames;
  alert: AlertConfigClassNames;
  avatar: AvatarConfigClassNames;
  badge: BadgeConfigClassNames;
  button: ButtonConfigClassNames;
  breadcrumb: BreadcrumbConfigClassNames;
  calendar: CalendarConfigClassNames;
  card: CardConfigClassNames;
  carousel: CarouselConfigClassNames;
  checkbox: CheckboxConfigClassNames;
  collapsible: CollapsibleConfigClassNames;
  datePicker: DatePickerConfigClassNames;
  dialog: DialogConfigClassNames;
  drawer: DrawerConfigClassNames;
  dropdown: DropdownConfigClassNames;
  form: FormConfigClassNames;
  formScope: FormScopeConfigClassNames;
  formField: FormFieldConfigClassNames;
  input: InputConfigClassNames;
  inputGroup: InputGroupConfigClassNames;
  menu: MenuConfigClassNames;
  menuItem: MenuItemConfigClassNames;
  multiValueInput: MultiValueInputConfigClassNames;
  notification: NotificationConfigClassNames;
  pagination: PaginationConfigClassNames;
  popover: PopoverConfigClassNames;
  progress: ProgressConfigClassNames;
  rate: RateConfigClassNames;
  radio: RadioConfigClassNames;
  resizable: ResizableConfigClassNames;
  rangeCalendar: RangeCalendarConfigClassNames;
  scroll: ScrollConfigClassNames;
  segment: SegmentConfigClassNames;
  select: SelectConfigClassNames;
  skeleton: SkeletonConfigClassNames;
  slider: SliderConfigClassNames;
  spinner: SpinnerConfigClassNames;
  steps: StepsConfigClassNames;
  switcher: SwitcherConfigClassNames;
  table: TableConfigClassNames;
  tabs: TabsConfigClassNames;
  tag: TagConfigClassNames;
  timeInput: TimeInputConfigClassNames;
  timeline: TimelineConfigClassNames;
  tooltip: TooltipConfigClassNames;
  upload: UploadConfigClassNames;
}>;