# Components

`@trymirio/mirio` has two layers. **Headless primitives** (`@trymirio/mirio/headless`) carry behavior and accessibility with no styling: form state, validation, conditional logic, page navigation, partial saves, focus management, labels and aria. **Styled components** (`@trymirio/mirio`) sit on top and look finished out of the box, authored in Tailwind and themed with `--mirio-*` CSS variables. Both are replaceable: restyle with the `theme`, `size`, `layout` and `classNames` props, variables or classes, or start from the primitives.

## Zero-markup form

```tsx
import { Form } from '@trymirio/mirio';
import { mirio } from '@/mirio/client';
import { waitlist } from '@/mirio/forms/waitlist';

<Form schema={waitlist} client={mirio} />
```

With no children, `Form` renders every page from the schema: one page gives you the fields and a submit button; several pages give you `MultiStep` with a progress line, Back and Next. After submit it shows the `settings.success` message, or redirects. Wrap the app once in [MirioProvider](/docs/components/provider.md) to drop the `client` prop.

## Composing

Children replace the automatic layout. `Field` renders any field by key (label, help, the right control, error); the controls, `Label`, `Help`, `FieldError`, `Submit`, `Page`, `Progress` and `MultiStep` can be arranged freely, mixed with your own JSX.

```tsx
import { Form, Field, Submit } from '@trymirio/mirio';

<Form schema={contact} client={mirio} className="grid gap-6">
  <div className="grid grid-cols-2 gap-4">
    <Field name="first_name" />
    <Field name="last_name" />
  </div>
  <Field name="email" />
  <Field name="message" />
  <Submit className="w-auto justify-self-end" />
</Form>
```

Every styled component accepts `className` (merged with tailwind-merge, so your utilities win) and renders `data-mirio="<name>"` for CSS. Hidden fields and pages (`showWhen`) render nothing. See [Styling](/docs/styling.md) for the three depths of customization.

## All components

| Component | One line |
| --- | --- |
| [Form](/docs/components/form.md) | The whole form from a schema; auto-renders or takes children. |
| [Field](/docs/components/field.md) | Label + help + the control for the field type + error, from one `name`. |
| [Input](/docs/components/input.md) | Single-line control for `short_text`, `email`, `phone`, `url`, `number`. |
| [Textarea](/docs/components/textarea.md) | Multi-line control for `long_text`. |
| [Select](/docs/components/select.md) | Styled native select for `dropdown`. |
| [Choice](/docs/components/choice.md) | Radio group (`single_choice`) or checkbox group (`multiple_choice`). |
| [YesNo](/docs/components/yes-no.md) | Two segmented buttons with radio semantics for `yes_no`. |
| [Rating](/docs/components/rating.md) | 1..max buttons with radio semantics and arrow keys for `rating`. |
| [DatePicker](/docs/components/date-picker.md) | Styled native date input for `date`. |
| [Consent](/docs/components/consent.md) | Checkbox with inline label for `consent`. |
| [Submit](/docs/components/submit.md) | Submit button with the label from `settings.submitLabel` and a loading state. |
| [Success](/docs/components/success.md) | The thank-you card from `settings.success`. |
| [MultiStep](/docs/components/multi-step.md) | One page at a time with Progress, Back/Next and Submit; also covers `Page` and `Progress`. |
| [Label, Help, FieldError](/docs/components/label-help-error.md) | The text pieces around a control, and the `requiredIndicator` option. |
| [MirioProvider](/docs/components/provider.md) | Provide the client and display options once. |
| [Headless](/docs/components/headless.md) | `useMirioForm`, `FormProvider`, `useForm`, `useField`, `usePage`, `useFormStatus`, `Honeypot`, `Turnstile`, with a reference table of everything the hook returns. |

## Behavior you get for free

- Client validation from the schema, with the same validator the server runs; format errors on blur, "required" on submit; focus moves to the first invalid control.
- Submit with an idempotency key and retries on network errors and 5xx; one logical submit never lands twice.
- Page URL, referrer and UTM parameters captured; a honeypot and time-to-submit as spam signals; Turnstile when a site key is set (Mirio checks it once it has the widget's secret key); agents that declare themselves (`actor`) are labeled.
- Partial saves when a visitor moves to the next step, never on keystrokes.
- Prefill from `initialValues`, `prefill: { query }` and `defaultValue`; `autocomplete` attributes from the schema.
- Conditional fields and pages ([Conditional logic](/docs/conditional-logic.md)), and `schedule` successes that land on a booking page with name and email filled in.
