HextaUI

Field: Errors from a form library or server

Pass invalid to the field and an errors array to <FieldError />. It takes the { message } shape React Hook Form and most schema libraries return. Duplicates are dropped, and several messages become a list. When the messages change, the new ones fade in and the height eases to fit, so nothing below jumps. Submit empty, then fix one rule at a time.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  Field,
  FieldError,
  FieldGroup,
  FieldLabel,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"

type Errors = {
  email?: { message: string }[]
  password?: { message: string }[]
}

export function FieldErrors() {
  const [errors, setErrors] = React.useState<Errors>({})

  return (
    <form
      className="w-full max-w-sm"
      onSubmit={(event) => {
        event.preventDefault()
        const data = new FormData(event.currentTarget)
        const password = String(data.get("password") ?? "")
        const next: Errors = {}
        if (!String(data.get("email") ?? "").includes("@")) {
          next.email = [{ message: "Enter a valid email." }]
        }
        const problems = []
        if (password.length < 8) {
          problems.push({ message: "Use at least 8 characters." })
        }
        if (!/\d/.test(password)) {
          problems.push({ message: "Include a number." })
        }
        if (problems.length > 0) {
          next.password = problems
        }
        setErrors(next)
      }}
    >
      <FieldGroup>
        <Field invalid={Boolean(errors.email)}>
          <FieldLabel>Email</FieldLabel>
          <Input name="email" autoComplete="email" />
          <FieldError errors={errors.email ?? []} />
        </Field>
        <Field invalid={Boolean(errors.password)}>
          <FieldLabel>Password</FieldLabel>
          <Input name="password" type="password" autoComplete="new-password" />
          <FieldError errors={errors.password ?? []} />
        </Field>
        <Button type="submit">Sign up</Button>
      </FieldGroup>
    </form>
  )
}

This adds the example as components/examples/field/errors.tsx, together with the Field component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/field-errors.json

To add only the component, follow the Field installation.

Props in this example

The Field props this example sets, from the API reference.

PropTypeDefault
invalidSet it from a form library or server response.
boolean–
PropTypeDefault
errorsErrors from a form library or server. Shown when the list has a message.
Array<{ message?: string } | undefined>–

Every prop is in the Field API reference.

See them all, with keyboard support and accessibility notes, on the Field page.