ErrorMessage

Validation text below a control. A sibling, not a Field part. id is required. There is no default role="alert" and no aria-live. invalid lives on the control or on Field.Root.

Mount the error only while it applies, and include its id in aria-describedby only then.

ErrorMessage owns its spacing. After a control, margin-block-start is field.label.gap (0.4rem). After Description, the sibling rule drops that to field.messages.gap (0.2rem). margin-block-end is 0.

const describedBy = invalid ? `${hintId} ${errorId}` : hintId

<Field.Root id={id} invalid={invalid} aria-describedby={describedBy}>
	<Field.TextInput value={email} onChange={(event) => setEmail(event.target.value)} />
</Field.Root>
<Description id={hintId}>We only use this for billing receipts.</Description>
{invalid ? <ErrorMessage id={errorId}>Enter an address that contains an @.</ErrorMessage> : null}
We only use this for billing receipts.Enter an address that contains an @.

To announce a submit-time error, pass role="alert" on this component. The package does not choose announcement policy.

When to use

When: Validation text below a control, after Description. Mount it and add its id to aria-describedby only while invalid; invalid lives on the control or Field.Root.

When not: Standing hints → Description. Showing while valid. Expecting auto-announce (no role="alert" by default; pass it for submit-time errors).

Props

ErrorMessage props
NameTypeRequiredDefaultDescription
idstringyes—Id the author lists in aria-describedby on the control or Field.Root.
childrenReact.ReactNodeno—Error text.
classNamestringno—Optional class on the span.