# Form Error Summary

> A submission error summary with links that focus the matching fields.

- Category: Forms
- Kind: component
- Page: https://uaiblocks.dev/components/form-error-summary
- Registry item: https://uaiblocks.dev/r/form-error-summary.json
- Source: https://github.com/victor-teles/uai/blob/main/src/registry/uai/components/form-error-summary.tsx

## Install

```bash
bunx shadcn@latest add https://uaiblocks.dev/r/form-error-summary.json
```

## Usage

```tsx
"use client";

import { useId, useState } from "react";
import {
  FormErrorSummary,
  FormErrorSummaryLink,
  FormErrorSummaryList,
  FormErrorSummaryTitle,
  type FormErrorSummaryVariant,
} from "@/components/ui/uai/form-error-summary";
import {
  FormField,
  FormFieldError,
  FormFieldInput,
  FormFieldLabel,
} from "@/components/ui/uai/form-field";

export function FormErrorSummaryPreview({
  variant = "card",
}: {
  variant?: FormErrorSummaryVariant;
}) {
  const emailId = useId();
  const nameId = useId();
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [submitted, setSubmitted] = useState(true);
  const invalidEmail = submitted && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  const invalidName = submitted && !name.trim();
  return (
    <form
      noValidate
      onSubmit={(event) => {
        event.preventDefault();
        setSubmitted(true);
      }}
      style={{ display: "grid", gap: 16 }}
    >
      {(invalidEmail || invalidName) && (
        <FormErrorSummary variant={variant}>
          <FormErrorSummaryTitle>Review your contact details</FormErrorSummaryTitle>
          <FormErrorSummaryList>
            {invalidEmail && (
              <FormErrorSummaryLink fieldId={emailId}>
                Enter a valid email address.
              </FormErrorSummaryLink>
            )}
            {invalidName && (
              <FormErrorSummaryLink fieldId={nameId}>Enter your full name.</FormErrorSummaryLink>
            )}
          </FormErrorSummaryList>
        </FormErrorSummary>
      )}
      <FormField
        inputId={emailId}
        value={email}
        onValueChange={setEmail}
        invalid={invalidEmail}
        required
      >
        <FormFieldLabel>Email</FormFieldLabel>
        <FormFieldInput
          name="email"
          type="email"
          autoComplete="email"
          placeholder="maya@northwind.studio"
        />
        <FormFieldError>Enter a valid email address.</FormFieldError>
      </FormField>
      <FormField
        inputId={nameId}
        value={name}
        onValueChange={setName}
        invalid={invalidName}
        required
      >
        <FormFieldLabel>Full name</FormFieldLabel>
        <FormFieldInput name="name" autoComplete="name" placeholder="Maya Chen" />
        <FormFieldError>Enter your full name.</FormFieldError>
      </FormField>
      {!invalidEmail && !invalidName && (
        <p role="status" style={{ margin: 0, fontSize: 12, color: "var(--uai-success)" }}>
          Contact details are ready.
        </p>
      )}
      <button
        type="submit"
        style={{
          justifySelf: "start",
          height: 30,
          padding: "0 14px",
          border: 0,
          borderRadius: 999,
          background: "var(--uai-accent)",
          color: "var(--uai-accent-foreground)",
          font: "inherit",
          fontSize: 12.5,
          fontWeight: 500,
        }}
      >
        Validate details
      </button>
    </form>
  );
}
```

## Anatomy

- `FormErrorSummary`
  - `FormErrorSummaryTitle`
  - `FormErrorSummaryList`
    - `FormErrorSummaryLink`
- `FormField`
  - `FormFieldLabel`
  - `FormFieldInput`
  - `FormFieldError`

## Accessibility

- Links retain fragment destinations and focus existing target fields. Render each link inside FormErrorSummaryList.
- Render the summary after a failed submission and set focusOnMount when it should receive focus; the title labels its alert.
- Use inputId on FormField or id on native fields. Structural list and link children may be reused without context.
