Skip to content
TopClass UI

Form

A plain form that posts with no script, and FormAction, whose action answers with errors that land on the matching fields.

split - size not measured yet

Form

split - size not measured yet

A plain form that posts with no script, and FormAction, whose action answers with errors that land on the matching fields.

Install
We never share it

The code

form.tsx
import { Button } from 'topclassui/button'
import { Field } from 'topclassui/field'
import { Input } from 'topclassui/input'
import { Form } from 'topclassui/form'

/** The subscribe form of "Your first component": it posts to /subscribe with no script, and the browser asks for the email first. */
export default function Demo() {
  return (
    <Form action="/subscribe" method="post" className="flex max-w-sm flex-col gap-4">
      <Field name="email" label="Email" hint="We never share it" required>
        {(control) => <Input {...control} type="email" autoComplete="email" fullWidth />}
      </Field>
      <Button type="submit">Subscribe</Button>
    </Form>
  )
}

A server Form cannot show what its action returns: hand each Field its error yourself, or use FormAction in a client file.

Import from the package

topclassui/form
import { Form } from 'topclassui/form'

Install once:npm i topclassui@beta zod

Examples

  • Form adds the flat export and the className merge, nothing else: no noValidate, so the browser's own required check runs before hydration and after.
  • FormAction runs React's useActionState: action(state, formData) returns the next state, whose errors are keyed by field name, as Zod's fieldErrors.
  • React resets the form when an action settles, so an action that returns errors returns the submitted values too, and the function child gives them back as defaults.
  • With no script a client function cannot post: pass permalink with a Server Action.
basic
We never share it
server-errors
This email is already subscribed
What can we help with?
Write at least 20 characters
Leave out the links
form-action
Try taken@example.com

In Arabic, right to left
لن نشاركه مع أحد

Props

No props of its own: it takes the attributes of the element it renders.

Keyboard and accessibility

The keyboard of Form
KeysWhat it does
EnterSubmits the form from a text control, as a native form does.
  • After an answer with errors the focus goes to the first control with aria-invalid="true", never on the first render.
  • The form carries aria-busy while the action is pending.

Right to left

Nothing of its own mirrors: the fields inside it read from the right, through their own logical classes.

Server and client

Renders on the server; the interactive part is a client component that ships only when it is used.

Files: index.tsx, client.tsx.

On the chip: split - size not measured yet.