Error summary
Lists the invalid fields at the top of a form after a failed submit, each one a link that moves focus to its control. Use it for forms with more than a couple of fields.
Installation
Set up Camaleo once (Installation), then import it. It goes with the Field parts.
import { ErrorSummary } from "@camaleo/react";Anatomy
A danger Alert with a title and a list of links. Every part has a data-slot you can target from CSS.
Examples
Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.
Fix 2 fields to continue.
Focus on submit
Press Continue with empty fields. The summary takes focus through ref and tabIndex={-1}, so it is read first, and it shrinks as you fix each field.
Errors from the server
Press Save. When your API rejects a value, show the same summary: people get one place to look whether the error came from the browser or the backend.
Fix 2 fields to continue.
Selects and checkboxes
target is the id of any focusable control. A checkbox's id lands on its hidden input, which hands focus to the visible box.
Fix 2 fields to continue.
In a long form
Click a link. The control scrolls to the middle of the screen, so a sticky header never hides the field you jumped to.
Fix 1 field to continue.
Fix 3 fields to continue.
One or many
Count the errors in the title and pick the wording with Intl.PluralRules, so "1 field" and "3 fields" both read right in every language.
Fix 1 field to continue.
With a written label
label adds a word like "Error". Some skins show it in place of the icon, and it gives the alert a text cue besides color.
In context
Error summaries sit at the top of real forms. These are whole pieces of UI you can copy, in the skin you picked.
Create your account
Free for 14 days. No card needed.
With react-hook-form and zod
Camaleo has no dependency on a form library. The signup form above wires react-hook-form and zod to Field and ErrorSummary; its Code tab has the whole file.
pnpm add react-hook-form zod @hookform/resolvers- The schema holds the messages.
zodResolver(schema)validates on submit, and each zod message becomesfieldState.error.message. Controllerconnects each control. PassfieldState.invalidtoField invalidand the message toFieldError match={fieldState.invalid}, so the error is linked to the control andaria-invalidis set.- Give every control an id. Use
useId()and put it on theInput(or theCheckbox,NativeSelectorRating, which pass it to the element that takes focus); the summary links to that same id. - Build the summary from
formState.errors. Show it whenisSubmittedand there are errors, map each invalid name to{ target: id, message: label }, and focus it whensubmitCountchanges. PassshouldFocusError: false, or react-hook-form moves focus to the first field instead. - Use
noValidateon the form. The browser's own bubbles would show before your messages.
const { control, handleSubmit, formState: { errors, isSubmitted, submitCount } } =
useForm<Values>({ resolver: zodResolver(schema), defaultValues, shouldFocusError: false });
const invalid = (Object.keys(labels) as (keyof Values)[]).filter((name) => errors[name]);
useEffect(() => {
if (submitCount > 0) summaryRef.current?.focus();
}, [submitCount]);
{isSubmitted && invalid.length > 0 && (
<ErrorSummary
ref={summaryRef}
tabIndex={-1}
title={`Fix ${invalid.length} fields to continue.`}
errors={invalid.map((name) => ({ target: ids[name], message: labels[name] }))}
/>
)}Guidelines
Fix 2 fields to continue.
One click or Enter takes people straight to what needs fixing.
There are errors in the form.
People have to hunt through the form for the red fields.
Fix 2 fields to continue.
"Card number: enter all 16 digits" works out of context, in a list of links.
Fix 2 fields to continue.
Two links called "Invalid value" can't be told apart by a screen reader user.
Props
target is the id of the invalid control; its link moves focus there.The other div attributes pass through, including ref and tabIndex: use them to move focus to the summary after a failed submit.
Styling hooks
Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the summary itself.
Attributes
Tokens it reads
Color
Shape & size
Type & motion
This component only
/* one error per line, only in the checkout */
.checkout [data-slot="error-summary-list"] {
flex-direction: column;
}Accessibility
- It renders with role="alert", so screen readers announce it as soon as it appears.
- Move focus to it after a failed submit (ref + tabIndex={-1}), so keyboard users start from the list instead of the submit button.
- Each link focuses the control itself, not just its label, so people can type right away.
- Keep the inline FieldError on every field too: the summary is the map, the field says what to change.