ConfigProvider
freeConfigProvider 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 ConfigProviderExamples
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.
| Prop | Description | Type | Default |
|---|---|---|---|
value | Complete configuration object used by descendant UI components. | Config | Required |
children | Subtree that receives the supplied configuration. | ReactNode | - |
Exports
| Export | Description |
|---|---|
ConfigProvider | Default provider component. |
useConfig | Reads the nearest provider value, falling back to defaultConfig. |
defaultConfig | Baseline config: light mode, English locale, medium controls, left-to-right direction, and no slot overrides. |
ConfigContext | Raw React context for advanced integrations. |
ConfigConsumer | Context 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;
}>;