Pho Design System

Form

Coordinates a set of Fields under one <form> — it runs native constraint validation on submit, focuses the first invalid control, and maps server-side errors back onto the matching fields. Built on Base UI Form, it renders a <form noValidate> and owns validation itself. For the fields inside it, reach for Input (which wraps Field) or compose Base UI Field directly.

Import

import { Form } from "@photon-ai/pho-ui/components/form";

Basic

Compose Fields (or Inputs, which wrap Field) and a submit Button. Give every control a name — that’s the key Form uses to validate it and to route server errors back to it.

<Form onSubmit={handleSubmit}>
  <Input name="email" label="Email" type="email" required />
  <Button type="submit">Subscribe</Button>
</Form>

Submitting

On submit, Form validates every field first. If any is invalid it blocks the submission and focuses the first invalid control. If all pass, it calls your onSubmit; pass onFormSubmit instead to receive the parsed field values keyed by name (it calls preventDefault for you).

<Form
  onFormSubmit={(values) => {
    // values.email — collected from each field's `name`
    subscribe(values.email);
  }}
>

</Form>

validationMode controls when fields validate: onSubmit (the default — validate on submit, then re-validate on change), onBlur, or onChange. A validationMode set on an individual Field wins over the form’s.

Server errors

Pass an errors object keyed by field name; Form flags the matching field invalid and, when the user next edits that field, clears its error automatically — there’s no clear-errors handler to wire. Rendering the message text requires a Field.Error part in the field, so with Pho’s Input drive its own invalid and hint props from the same error state:

<Form errors={serverErrors}>
  <Input
    name="email"
    label="Email"
    type="email"
    invalid={Boolean(serverErrors.email)}
    hint={serverErrors.email}
  />
  <Button type="submit">Subscribe</Button>
</Form>

Props

Accessibility

Form renders a native <form> element, so it inherits the platform’s form semantics; its job is to make validation legible to assistive tech.

Keyboard: Enter in a field submits the form, which runs validation before any handler fires — so keep the submit Button typed submit and inside the Form.

Best practices