Docs
ComponentsMirioProvider
View as Markdown(opens in a new tab)

MirioProvider

Provide the client and display options once so every Form can omit them.

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 preview for its effect.

Usage

// 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.
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.

<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>
<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).

Accessibility

No effect on its own; see Label for how the required indicator is exposed (aria-hidden mark, aria-required on the control).

Form, Theming, Label, Help, FieldError, Client SDK