---
title: MirioProvider
description: Provide the client and display options once so every Form can omit them.
---
# MirioProvider

Wrap your app (or a layout) once with `MirioProvider` and every `Form` below it finds the client through context. It also carries site-wide display options: `theme`, `size`, `classNames`, `requiredIndicator` and `optionalIndicator`.

## Preview
`MirioProvider` renders nothing visible. See the [required indicator](/docs/components/label-help-error.md#variants-and-states) preview for its effect.

## Usage
```tsx
// app/providers.tsx (Next.js app router: a client component, because the client holds functions)
'use client';
import { MirioProvider } from '@trymirio/mirio';
import { mirio } from '@/mirio/client';

export function Providers({ children }: { children: React.ReactNode }) {
  return <MirioProvider client={mirio}>{children}</MirioProvider>;
}

// any page, even a server component: the schema is plain data
import { Form } from '@trymirio/mirio';
import { waitlist } from '@/mirio/forms/waitlist';

export default function Page() {
  return <Form schema={waitlist} />;
}
```

## Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `client` | `MirioClient` | inherited from a parent provider | From `createClient`. Optional when nesting: a provider without `client` keeps the parent's. |
| `requiredIndicator` | `ReactNode \| null` | inherited, else nothing | What `Label` appends to required fields. |
| `optionalIndicator` | `ReactNode \| null` | inherited, else muted "Optional" | What `Label` appends to optional fields. `null` for nothing. |
| `theme` | `MirioTheme` | inherited | Colors, `radius`, `font`, `colorScheme` for every form below; merged per key with a parent provider's and with each form's (the form wins). See [Theming](/docs/theming.md). |
| `size` | `'sm' \| 'md' \| 'lg'` | inherited, else `'md'` | Default size for every form below; a form's `size` wins. |
| `classNames` | `Partial<Record<Slot, string>>` | inherited | Classes per part for every form below. Per slot, the parent's, this provider's and the form's classes are all kept, in that order, then the component's own `className`. |
| `children` | `ReactNode` | — | |

Renders no DOM element and has no `className` or `data-mirio`.

Hooks: `useMirioClient()` returns the nearest client or `null`; `useFormOptions()` returns the merged display options; `useSlot(slot)` returns the merged classes for one slot (for your own components). `layout` is a `Form` prop only. `Form` scopes its own options (merged over the provider's) to its subtree.

## Variants and states
Nesting merges: an inner provider can change one option and keep the rest.

```tsx
<MirioProvider client={mirio} theme={{ primary: 'var(--brand)', radius: 'lg' }} size="sm" classNames={{ label: 'uppercase tracking-wide' }}>
  <Form schema={waitlist} />                                    {/* brand primary, lg radius, sm, uppercase labels */}
  <Form schema={demo} size="md" theme={{ colorScheme: 'dark' }} /> {/* same, but md and dark */}
</MirioProvider>
```


```tsx
<MirioProvider client={mirio} optionalIndicator={<span> (optional)</span>}>
  …most forms…
  <MirioProvider requiredIndicator={<span> (required)</span>} optionalIndicator={null}>
    <Form schema={application} />   {/* same client, different marks */}
  </MirioProvider>
</MirioProvider>
```

A `Form` with its own `client` prop ignores the context client; `requiredIndicator` on `Form` overrides the provider's for that form only.

## Customization
Renders no DOM. `theme` becomes inline variables on each `Form` root; you can also set `--mirio-*` variables on `:root` or a wrapper (see [Styling](/docs/styling.md)).

## Accessibility
No effect on its own; see [Label](/docs/components/label-help-error.md) for how the required indicator is exposed (`aria-hidden` mark, `aria-required` on the control).

## Related
[Form](/docs/components/form.md), [Theming](/docs/theming.md), [Label, Help, FieldError](/docs/components/label-help-error.md), [Client SDK](/docs/api.md)
