> Native Solid 2 fork. Original documentation and designs © WorkOS; historical posts retain their original context.

# Form

Collect information from your users using validation rules.

## Features

- Built on top of the native browser [constraint validation API.](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation)

- Supports built-in validation.

- Supports custom validation.

- Full customization of validation messages.

- Accessible validation messages.

- Supports client-side and server-side scenarios.

- Focus is fully managed.

## Anatomy

Import all parts and piece them together.

```jsx
import { Form } from "@radix-solid/primitives";

export default () => <Form.Root>

		<Form.Field name="email">

			<Form.Label />

			<Form.Control />

			<Form.Message />

			<Form.ValidityState>{validity => validity?.valid ? "Valid" : null}</Form.ValidityState>

		</Form.Field>



		<Form.Message name="email" />

		<Form.ValidityState name="email">{validity => validity?.valid ? "Valid" : null}</Form.ValidityState>



		<Form.Submit />

	</Form.Root>;
```

## API Reference

### Root

Contains all the parts of a form.

| Prop                                                                                                                                                                    | Type       | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean`  | `false` |
| `onClearServerErrors`Event handler called when the form is submitted or reset and the server errors need to be cleared.                                                 | `function` | —       |

### Field

The wrapper for a field. It handles id/name and label accessibility automatically.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |
| `name*`The name of the field that will be passed down to the control and used to match with validation messages.                                                        | `string`  | —       |
| `serverInvalid`Use this prop to mark the field as invalid on the server.                                                                                                | `boolean` | —       |

| Data attribute   | Values                            |
| ---------------- | --------------------------------- |
| `[data-invalid]` | Present when the field is invalid |
| `[data-valid]`   | Present when the field is valid   |

### Label

A label element which is automatically wired when nested inside a `Field` part.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |

| Data attribute   | Values                            |
| ---------------- | --------------------------------- |
| `[data-invalid]` | Present when the field is invalid |
| `[data-valid]`   | Present when the field is valid   |

### Control

A control element (by default an `input`) which is automatically wired when nested inside a `Field` part.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |

| Data attribute   | Values                            |
| ---------------- | --------------------------------- |
| `[data-invalid]` | Present when the field is invalid |
| `[data-valid]`   | Present when the field is valid   |

### Message

A validation message which is automatically wired (functionality and accessibility) to a given control when nested inside a `Field` part. It can be used for built-in and custom client-side validation, as well as server-side validation. When used outside a `Field` you must pass a `name` prop matching a field.

`Form.Message` accepts a `match` prop which is used to determine when the message should show. It matches the native HTML validity state (`ValidityState` on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState)) which validates against attributes such as `required`, `min`, `max`. The message will show if the given `match` is `true` on the control’s validity state.

You can also pass a function to `match` to provide custom validation rules.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |
| `match`Used to indicate on which condition the message should be visible.                                                                                               | `Matcher` | —       |
| `forceMatch`Forces the message to be shown. This is useful when using server-side validation.                                                                           | `boolean` | `false` |
| `name`Used to target a specific field by name when rendering outside of a `Field` part.                                                                                 | `string`  | —       |

### ValidityState

Use this render-prop component to access a given field’s validity state in render (see `ValidityState` on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState)). A field's validity is available automatically when nested inside a `Field` part, otherwise you must pass a `name` prop to associate it.

| Prop                                                                                    | Type       | Default |
| --------------------------------------------------------------------------------------- | ---------- | ------- |
| `children`A render function that receives the validity state of the field.              | `function` | —       |
| `name`Used to target a specific field by name when rendering outside of a `Field` part. | `string`   | —       |

### Submit

The submit button.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |

## Examples

### Composing with your own components

Using `asChild` you can compose the `Form` primitive parts with your own components.

```jsx
<Form.Field name="name">

	<Form.Label>Full name</Form.Label>

	<Form.Control asChild>{target => target(TextField.Root, {

        "variant": "surface"

      })}</Form.Control>

</Form.Field>
```

It can also be used to compose other types of controls, such as a `select`:

```jsx
<Form.Field name="country">

	<Form.Label>Country</Form.Label>

	<Form.Control asChild>{target => target("select", {

        children: <>

			<option value="uk">United Kingdom</option>…

		</>

      })}</Form.Control>

</Form.Field>
```

> Note: At the moment, it is not possible to compose `Form` with Radix's other form primitives such as `Checkbox`, `Select`, etc. We are working on a solution for this.

### Providing your own validation messages

When no `children` are provided, `Form.Message` will render a default error message for the given `match`.

```jsx
// will yield "This value is missing"

<Form.Message match="valueMissing" />;
```

You can provide a more meaningful message by passing your own `children`. This is also useful for internationalization.

```jsx
// will yield "Please provide a name"

<Form.Message match="valueMissing">Please provide a name</Form.Message>;
```

### Custom validation

On top of all the built-in client-side validation matches described above you can also provide your own custom validation whilst still making use of the platform's validation abilities. It uses the `customError` type present in the [constraint validition API](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation).

You can pass your own validation function into the `match` prop on `Form.Message`. Here's an example:

```jsx
<Form.Field name="name">

	<Form.Label>Full name</Form.Label>

	<Form.Control />

	<Form.Message match={(value, formData) => value !== "John"}>

		Only John is allowed.

	</Form.Message>

</Form.Field>
```

> `match` will be called with the current value of the control as first argument and the entire `FormData` as second argument. `match` can also be an `async` function (or return a promise) to perform async validation.

### Styling based on validity

We add `data-valid` and `data-invalid` attributes to the relevant parts. Use it to style your components accordingly. Here is an example styling the `Label` part.

```jsx
//index.tsx



import { Form } from "@radix-solid/primitives";

export default () => <Form.Root>

		<Form.Field name="email">

			<Form.Label class="FormLabel">Email</Form.Label>

			<Form.Control type="email" />

		</Form.Field>

	</Form.Root>;
```

```css
/* styles.css */

.FormLabel[data-invalid] {

	color: red;

}

.FormLabel[data-valid] {

	color: green;

}
```

### Accessing the validity state for more control

You may need to access the raw validity state of a field in order to display your own icons, or interface with a component library via it's defined props. You can do this by using the `Form.ValidityState` part:

```jsx
<Form.Field name="name">

	<Form.Label>Full name</Form.Label>

	<Form.ValidityState>

		{validity => <Form.Control asChild>{target => target(TextField.Root, {

          "variant": "surface",

          "aria-invalid": validity ? validity.valid ? "false" : "true" : undefined

        })}</Form.Control>}

	</Form.ValidityState>

</Form.Field>
```

### Server-side validation

The component also supports server-side validation using the same `Form.Message` component. You can re-use the same messages you defined for client-side errors by passing a `forceMatch` prop which will force the message to show regardless of the client-side matching logic.

If the message doesn't exist on the client-side, you can render a `Form.Message` without a `match` too. The field is marked as invalid by passing a `serverInvalid` boolean prop to the `Form.Field` part.

Pass your application's submit function. It resolves to invalid-field flags; request failures are displayed separately.

```tsx
import { createSignal } from "solid-js";

import { Form } from "@radix-solid/primitives";

type ServerErrors = { email: boolean; password: boolean };

function Page(props: { submit: (data: FormData) => Promise<ServerErrors> }) {

  const [serverErrors, setServerErrors] = createSignal<ServerErrors>({

    email: false,

    password: false

  });

  const [requestError, setRequestError] = createSignal<string>();

  return <Form.Root
  // Only triggered after client-side validation succeeds.
  onSubmit={async event => {
    event.preventDefault();
    setRequestError(undefined);
    try {
      setServerErrors(await props.submit(new FormData(event.currentTarget)));
    } catch (error) {
      setRequestError(error instanceof Error ? error.message : "Unable to submit the form.");
    }
  }} onClearServerErrors={() => setServerErrors({
    email: false,
    password: false
  })}>

			<Form.Field name="email" serverInvalid={serverErrors().email}>

				<Form.Label>Email address</Form.Label>

				<Form.Control type="email" required />

				<Form.Message match="valueMissing">

					Please enter your email.

				</Form.Message>

				<Form.Message match="typeMismatch" forceMatch={serverErrors().email}>

					Please provide a valid email.

				</Form.Message>

			</Form.Field>



			<Form.Field name="password" serverInvalid={serverErrors().password}>

				<Form.Label>Password</Form.Label>

				<Form.Control type="password" required />

				<Form.Message match="valueMissing">

					Please enter a password.

				</Form.Message>

				{serverErrors().password && <Form.Message>

						Please provide a valid password. It should contain at least 1 number

						and 1 special character.

					</Form.Message>}

			</Form.Field>

			{requestError() && <p role="alert">{requestError()}</p>}



			<Form.Submit>Submit</Form.Submit>

		</Form.Root>;

}
```

You should clear the server errors using the `onClearServerErrors` callback prop on the `Form.Root` part. It will clear the server errors before the form is re-submitted, and when the form is reset.

In addition, this provides control over when to reset single server errors. For example you could reset the email server error as soon as the user edits it:

```tsx
function EmailField(props: { serverInvalid: boolean; onClearServerError: () => void }) {

  return <Form.Field name="email" serverInvalid={props.serverInvalid}>

    <Form.Label>Email address</Form.Label>

    <Form.Control type="email" onInput={props.onClearServerError} />

    <Form.Message match="valueMissing">Please enter your email.</Form.Message>

    <Form.Message match="typeMismatch" forceMatch={props.serverInvalid}>

      Please provide a valid email.

    </Form.Message>

  </Form.Field>;

}
```

## Accessibility

The component follows the "inline errors" pattern for validation:

- Label and control are associated using the `name` provided on `Form.Field`
- When one or more client-side error messages display, they are automatically associated with their matching control and announced accordingly
- Focus is moved to the first invalid control
