HextaUI

Field: Custom validation

Pass validate to check anything, including async lookups. Return a message to fail or nothing to pass. With validationMode="onChange" and validationDebounceTime, it runs while typing without firing on every key. Try “ada”.

Checked as you type.

"use client"

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

const taken = ["admin", "ada", "hexta"]

async function checkUsername(value: unknown) {
  const name = String(value ?? "")
    .trim()
    .toLowerCase()
  if (name.length === 0) {
    return null
  }
  if (!/^[a-z0-9_]+$/.test(name)) {
    return "Use letters, numbers and underscores only."
  }
  await new Promise((resolve) => setTimeout(resolve, 400))
  return taken.includes(name) ? `“${name}” is taken.` : null
}

export function FieldCustomValidation() {
  return (
    <Field
      validationMode="onChange"
      validationDebounceTime={300}
      validate={checkUsername}
      className="max-w-sm"
    >
      <FieldLabel>Username</FieldLabel>
      <Input placeholder="Try “ada”" autoComplete="off" />
      <FieldDescription>Checked as you type.</FieldDescription>
      <FieldError />
    </Field>
  )
}

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

pnpm dlx shadcn@latest add https://hextaui.com/r/field-custom-validation.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
validateReturn one or more messages to fail, or nothing to pass. Async is supported.
(value, formValues) => string | string[] | null | Promise<…>–
validationMode
"onSubmit" | "onBlur" | "onChange""onSubmit"
validationDebounceTimeMilliseconds to wait between onChange validations.
number0

Every prop is in the Field API reference.

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