Validation

Communicate the success or failure of a field. A control carries the isValid / isInvalid state; a sibling FormFeedback shows the matching message. It’s a sibling-driven contract — the control owns the class and the feedback reacts to it.

Import

tsx
import { FormControl, FormFeedback } from '@metatoy/bootstrap-styled';

Valid & invalid feedback

Set isValid or isInvalid on the control — it emits the .is-valid / .is-invalid class and the green/red border. Place a FormFeedback with the matching type immediately after it, as a sibling; the feedback is hidden until the preceding sibling is marked, then reveals.

Tooltip feedback

Add tooltip to FormFeedback for an absolutely-positioned overlay instead of a block message that reflows the layout. Give the wrapping element position: relative so the tooltip anchors to the field.

Browser-driven validation

Add the was-validated class to the <form> and the browser’s native :valid / :invalid pseudo-classes drive the feedback — no isValid / isInvalid props needed. Use noValidate on the form so the browser shows your styled messages instead of its own bubbles.

A live validated form

Drive isValid / isInvalid from your own state to validate on submit. Here the control stays unmarked until the form is submitted, then reflects whether the email matches:

Props

FormFeedback

PropTypeDefaultDescription
type"valid" | "invalid"Valid (green) or invalid (red) feedback. Default `invalid`.
tooltipbooleanRender the tooltip variant (absolutely positioned overlay) instead of the inline block message.

FormFeedback also accepts all native <div> attributes. The isValid / isInvalid state lives on the control — see FormControl and FormSelect.

Theming

Feedback and control states read the dedicated validation tokens: --bs-form-valid-color / --bs-form-invalid-color for the message text, --bs-form-valid-border-color / --bs-form-invalid-border-color for the control border, and --bs-success / --bs-danger for the tooltip fills. Override them to match your palette:

tsx
<div style={{ '--bs-form-invalid-color': '#b91c1c', '--bs-danger': '#dc2626' }}>
<FormControl isInvalid defaultValue="nope" aria-label="Username" />
<FormFeedback type="invalid">Please choose a valid username.</FormFeedback>
</div>

Accessibility

Color alone can’t carry the valid/invalid meaning, so always pair the state with a text FormFeedback message. Wire the control to its message with aria-describedby and set aria-invalid when a field is in error so assistive tech announces the problem. Keep submit-time validation focused: move focus to the first invalid control so keyboard and screen-reader users land on it.

Explore in Ladle

Open in Ladle