Ties a label, instructions and an error message to one form control.
Code
import { Field, FieldControl, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
<Field required invalid={invalid}>
<FieldLabel>Email</FieldLabel>
<FieldControl>
<Input type="email" />
</FieldControl>
<FieldDescription>We send receipts here.</FieldDescription>
<FieldError>Enter an email like name@example.com.</FieldError>
</Field>
Examples
Example source
var P = window.PUI, h = React.createElement;
function Demo() {
var s = React.useState('maya@'), v = s[0];
var invalid = !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v);
return h('div', { className: 'pui-stage', style: { padding: 0, maxWidth: 360 } },
h(P.Field, { required: true, invalid: invalid },
h(P.FieldLabel, null, 'Email'),
h(P.FieldControl, null, h(P.Input, { type: 'email', value: v, onChange: function (e) { s[1](e.target.value); } })),
h(P.FieldDescription, null, 'We send receipts here.'),
h(P.FieldError, null, 'Enter an email like name@example.com.')),
h(P.Field, null,
h(P.FieldLabel, null, 'Company'),
h(P.FieldControl, null, h(P.Input, { placeholder: 'E.g. Acme Inc.' }))));
}
ReactDOM.createRoot(document.getElementById('preview')).render(h(Demo));
Usage
What you provide
Field with required and invalid (set invalid after validation finds a problem, not before the person had a chance to type). controlId is optional; one is generated.
FieldLabel: the visible label. Optional fields get "(optional)" automatically.
FieldControl: wraps exactly one control (Input, Textarea, PasswordInput, SelectTrigger) and gives it id, required, aria-invalid and aria-describedby.
FieldDescription: instructions, formats and limits, shown before the person types.
FieldError: what is wrong and how to fix it. Rendered only while invalid is true.
Usage
Error messages are concrete: "Enter an email like name@example.com", not "Invalid value". Tell empty, wrong format and business rules apart; a server failure is not a field error.
Keep the values after an invalid submit. Move focus to an error summary or to the first invalid field, and never put passwords in messages.
Don't announce the same error through focus and a live region at once.
Accessibility
The label stays visible and is associated with the control; instructions and the error are linked through aria-describedby, and aria-invalid is set only while an error is detected.
Required fields get required; errors are written in text, never only as a red border or an icon.
After a rejected submit, focus goes to an error summary (with links to each field) or to the first invalid field. When fixed, the message and aria-invalid are removed without clearing other errors.
Validating while typing keeps focus and input intact and doesn't announce on every key.
Adapted from Magoo 1.6.0 by Marcelo Sales: Form validation (validacao-formularios), Input "text" (input-text). Magoo is educational guidance; test the behavior in your implementation.