# Providers and locale

Configure shared dimensions, theme propagation, locale, and component services.

## Shared UI configuration

The kit works without SiteplaneUIProvider: controlSize defaults to `lg`, density to `default` and radius to `md`. Explicit size props override the inherited size. The sizes are `sm`, `md`, `lg` and `xl`. Add a provider only when you need a shared override. It inherits unspecified values from an outer provider and exposes a display-contents scope.

```tsx
"use client";

import { SiteplaneUIProvider } from "@/siteplane/system/provider/siteplane-ui-provider";
import { Button } from "@/siteplane/components/button";

export default function Example() {
  return (
    <SiteplaneUIProvider controlSize="lg" density="compact" radius="sm">
      <Button>Continue</Button>
    </SiteplaneUIProvider>
  );
}
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| controlSize | sm \| md \| lg \| xl | lg | Inherited by controls that support size. |
| density | compact \| default | default | Inherited by Card, Resource List and Filter Bar. |
| radius | none \| sm \| md \| lg \| xl | md | Radius values: 0 / 0.5 / 0.625 / 0.875 / 1.25rem. |
| data-theme | light \| dark | inherited / unset | Explicit theme propagated to kit portal scopes. |
| nonce | string | inherited / unset | The nonce of a Content Security Policy. The provider hands it to React Aria, through a meta element in the head, and to Base UI's CSPProvider. See Content Security Policy in Installation. |
| children / className / style | HTML div props | display: contents | Provider content and scope attributes. |

Do not assume a provider adds a prop to every component. Use each reference’s own API. `useSiteplaneUI` reads resolved configuration; application code rarely needs lower-level resolution or portal helpers.

## Control size

`controlSize` sizes every control without a `size` of its own, such as Button, Input, Select, Toggle, Tabs, Badge, the rows of Table and the days of Calendar. The search row and the results of [Command](/docs/components/command/) and the chips of a multiple [Combobox](/docs/components/combobox/#multiple-selection) follow it too. A `size` prop fixes a control at that size, whatever the provider says.

Some parts are a step smaller or larger than the controls beside them by design, such as compact period toggles in a card header or a verification code field. Give such a part its size at the default `lg` through `useRelativeControlSize`. It keeps its steps from `lg` at every control size, so the composition looks as designed at `lg` and keeps its proportions at the others. The [Patterns](/docs/patterns/) size their parts this way.

```tsx
"use client";

import { useRelativeControlSize } from "@/siteplane/system/provider/siteplane-ui-provider";
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/siteplane/components/toggle-group";

export function PeriodToggle() {
  // Two steps below lg: sm up to lg, md at xl.
  const size = useRelativeControlSize("sm");
  return (
    <ToggleGroup
      aria-label="Period"
      defaultValue={["7d"]}
      size={size}
      variant="outline"
    >
      <ToggleGroupItem value="7d">7D</ToggleGroupItem>
      <ToggleGroupItem value="30d">30D</ToggleGroupItem>
    </ToggleGroup>
  );
}
```

| Size at `lg`   | At `sm` | At `md` | At `lg` | At `xl` |
| -------------- | ------- | ------- | ------- | ------- |
| `xs`, a Button | `xs`    | `xs`    | `xs`    | `sm`    |
| `sm`           | `sm`    | `sm`    | `sm`    | `md`    |
| `md`           | `sm`    | `sm`    | `md`    | `lg`    |
| `lg`           | `sm`    | `md`    | `lg`    | `xl`    |
| `xl`           | `md`    | `lg`    | `xl`    | `xl`    |

The scale ends at `sm` and `xl`, so a part never leaves it; only a part that is `xs` at `lg`, a Button size, goes below `sm`. Outside a component, `resolveRelativeControlSize(sizeAtLg, controlSize)` gives the same result.

## Radius

`radius` sets one base, `--radius`, and the corners of the kit follow it: 0, 8, 10, 14 and 20 px for `none`, `sm`, `md`, `lg` and `xl`. Each role takes a fixed share of the base, so controls, surfaces and dialogs keep their proportions at every setting.

| Role token               | Share of the base | At `md` | Used by                                                      |
| ------------------------ | ----------------- | ------- | ------------------------------------------------------------ |
| `--sp-rw-radius-xs`      | 0.4               | 4 px    | Badge, Kbd, Checkbox, Skeleton, chips                        |
| `--sp-rw-radius-sm`      | 0.6               | 6 px    | Tooltip, the smallest buttons                                |
| `--sp-rw-radius-control` | 0.8               | 8 px    | Button, Input, Select, Toggle, Tabs, menu rows               |
| `--sp-rw-radius-surface` | 1.2               | 12 px   | Card, Popover, Menu and the other floating panels, xl fields |
| `--sp-rw-radius-dialog`  | 1.6               | 16 px   | Dialog, and the inset Drawer from 640 px                     |

A Button is 6.4 px round at `sm`, 8 px at `md` and 11.2 px at `lg`. Alert Dialog and the rounded corners of the default Drawer take 1.5 times the dialog radius, 24 px at `md`. Pills, the Radio, the Slider and Avatar stay fully round at every setting. Three parts keep a shape of their own instead of a share of the base: Bar Chart bars keep their 8 px ends, the diamond marker of [Timeline](/docs/components/timeline/) keeps its 2 px corners, and the swatches of [Color Swatch Picker](/docs/components/color-swatch-picker/) stay round, except that `none` squares them and `sm` gives them 6 px corners. Tailwind’s `rounded-sm` to `rounded-4xl` utilities follow the same base, and the kit’s `rounded-control`, `rounded-surface` and `rounded-overlay` take the control, surface and dialog radius.

Without a provider the page uses the `md` base, so an application without one looks like one with the default. A provider with another radius applies it to its children and to the overlays they open. To change one role at the default radius, set its token on `:root` after the base import, as the badge example in [Theming](/docs/customization/theming/#shared-dimensions) does; a provider with another radius derives its own values.

## Locale

Install `@siteplane/locale` when using locale directly. Date components include the support they require through registry dependencies.

```tsx
import { SiteplaneLocaleProvider } from "@/siteplane/system/locale/siteplane-locale-provider";
import { Calendar } from "@/siteplane/components/calendar";

<SiteplaneLocaleProvider locale="en-GB">
  <Calendar aria-label="Choose a date" />
</SiteplaneLocaleProvider>;
```

SiteplaneLocaleProvider wraps React Aria’s I18nProvider and requires a locale string. It controls date and number formatting in React Aria–based components, not arbitrary application text. Some date wrappers expose their own locale prop; TimeField does not. Check each date page for its exact value representation.

Calendar and the date picker wrappers take JavaScript Date values as local calendar dates. Convert to your backend’s chosen representation explicitly. Do not silently serialize a date-only value as an instant or invent a timezone prop on a wrapper that does not expose one.

## Component services

[TooltipProvider](/docs/components/tooltip/) coordinates tooltip timing. [ToastProvider](/docs/components/toast/) manages a toast viewport; mount one per manager near the application root. SidebarProvider already includes its own tooltip provider and owns desktop/mobile navigation state.

[Motion configuration](/docs/customization/motion/) is separate from SiteplaneUIProvider. ThemeToggles similarly present controls; your application remains responsible for storing and applying the selected theme.
