Use `data-bs-validate="valid"` to also show success styling on valid fields. Add `required` to each form input and `.invalid-feedback` to provide field-specific error messages. If you enable valid styling, use `.valid-feedback` for success messages.
+**For accessibility,** add `aria-describedby` to each form control, pointing to the `id` of its feedback message. This ensures screen readers announce the error when the user focuses an invalid field. The example JavaScript below also sets `aria-invalid` on each control at submit time and clears it as users correct their input.
+
For example, try to submit the form below; our JavaScript will intercept the submit button and relay feedback to you.
<Example code={`<form class="grid grid-cols-1 gap-5" data-bs-validate novalidate><!-- [!code highlight] -->
<div class="grid gap-5">
<div class="form-field md:g-col-6">
<label for="validationCustom01" class="form-label">Name</label>
- <input type="text" class="form-control" id="validationCustom01" value="Mark Otto" required><!-- [!code highlight] -->
- <div class="invalid-feedback">Full name is required</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationCustom01" value="Mark Otto" required aria-describedby="validationCustom01Feedback"><!-- [!code highlight] -->
+ <div id="validationCustom01Feedback" class="invalid-feedback">Full name is required</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-6">
<label for="validationCustomUsername" class="form-label">Donation amount</label>
<div class="input-group">
<span class="input-group-text" id="inputGroupPrepend">$</span>
- <input type="number" class="form-control" value="100" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required><!-- [!code highlight] -->
+ <input type="number" class="form-control" value="100" id="validationCustomUsername" aria-describedby="inputGroupPrepend validationCustomUsernameFeedback" required><!-- [!code highlight] -->
</div>
- <div class="invalid-feedback">Please enter a donation amount</div><!-- [!code highlight] -->
+ <div id="validationCustomUsernameFeedback" class="invalid-feedback">Please enter a donation amount</div><!-- [!code highlight] -->
</div>
</div>
<div class="form-field">
<label for="validationCustomAddress" class="form-label">Address</label>
- <input type="text" class="form-control" id="validationCustomAddress" value="1234 Main St" required><!-- [!code highlight] -->
- <div class="invalid-feedback">Please enter a mailing address</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationCustomAddress" value="1234 Main St" required aria-describedby="validationCustomAddressFeedback"><!-- [!code highlight] -->
+ <div id="validationCustomAddressFeedback" class="invalid-feedback">Please enter a mailing address</div><!-- [!code highlight] -->
</div>
<div class="grid gap-5">
<div class="form-field md:g-col-6">
<label for="validationCustom03" class="form-label">City</label>
- <input type="text" class="form-control" id="validationCustom03" required><!-- [!code highlight] -->
- <div class="invalid-feedback">Please provide a city</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationCustom03" required aria-describedby="validationCustom03Feedback"><!-- [!code highlight] -->
+ <div id="validationCustom03Feedback" class="invalid-feedback">Please provide a city</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-4">
<label for="validationCustom04" class="form-label">State</label>
- <select class="form-control" id="validationCustom04" required><!-- [!code highlight] -->
+ <select class="form-control" id="validationCustom04" required aria-describedby="validationCustom04Feedback"><!-- [!code highlight] -->
<option selected disabled value="">Choose…</option>
<option>...</option>
</select>
- <div class="invalid-feedback">Please select a state</div><!-- [!code highlight] -->
+ <div id="validationCustom04Feedback" class="invalid-feedback">Please select a state</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-2">
<label for="validationCustom05" class="form-label">Zip</label>
- <input type="text" class="form-control" id="validationCustom05" required><!-- [!code highlight] -->
- <div class="invalid-feedback">Required</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationCustom05" required aria-describedby="validationCustom05Feedback"><!-- [!code highlight] -->
+ <div id="validationCustom05Feedback" class="invalid-feedback">Required</div><!-- [!code highlight] -->
</div>
</div>
<div class="grid gap-5">
<div class="form-field md:g-col-6">
<label for="validationServer01" class="form-label">Name</label>
- <input type="text" class="form-control is-valid" id="validationServer01" value="Mark Otto"><!-- [!code highlight] -->
- <div class="valid-feedback">Looks great!</div><!-- [!code highlight] -->
- <div class="invalid-feedback">Full name is required</div><!-- [!code highlight] -->
+ <input type="text" class="form-control is-valid" id="validationServer01" value="Mark Otto" aria-describedby="validationServer01Valid validationServer01Invalid"><!-- [!code highlight] -->
+ <div id="validationServer01Valid" class="valid-feedback">Looks great!</div><!-- [!code highlight] -->
+ <div id="validationServer01Invalid" class="invalid-feedback">Full name is required</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-6">
<label for="validationServerDonation" class="form-label">Donation amount</label>
<div class="form-field">
<label for="validationServerAddress" class="form-label">Address</label>
- <input type="text" class="form-control is-valid" id="validationServerAddress" value="1234 Main St"><!-- [!code highlight] -->
- <div class="valid-feedback">Looks great!</div><!-- [!code highlight] -->
- <div class="invalid-feedback">Please enter a mailing address</div>
+ <input type="text" class="form-control is-valid" id="validationServerAddress" value="1234 Main St" aria-describedby="validationServerAddressValid validationServerAddressInvalid"><!-- [!code highlight] -->
+ <div id="validationServerAddressValid" class="valid-feedback">Looks great!</div><!-- [!code highlight] -->
+ <div id="validationServerAddressInvalid" class="invalid-feedback">Please enter a mailing address</div>
</div>
<div class="grid gap-5">
<Example code={`<form class="vstack gap-5">
<div class="form-field">
<label for="validationTextarea" class="form-label">Textarea</label>
- <textarea class="form-control is-invalid" id="validationTextarea" placeholder="Required example textarea" required></textarea>
- <div class="invalid-feedback">
+ <textarea class="form-control is-invalid" id="validationTextarea" placeholder="Required example textarea" required aria-describedby="validationTextareaFeedback"></textarea>
+ <div id="validationTextareaFeedback" class="invalid-feedback">
Please enter a message in the textarea.
</div>
</div>
<label class="form-label">Checkbox</label>
<div class="form-field">
<div class="check">
- <input type="checkbox" class="is-invalid" id="validationFormCheck1" required>
+ <input type="checkbox" class="is-invalid" id="validationFormCheck1" required aria-describedby="validationFormCheck1Feedback">
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'>
<path class="checked" fill='none' stroke='currentcolor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m4 8 3 3 5-5'/>
<path class="indeterminate" fill='none' stroke='currentcolor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4.5 8.5h6'/>
</div>
<div class="form-field-content">
<label for="validationFormCheck1">Check this checkbox</label>
- <div class="invalid-feedback">Example invalid feedback text</div>
+ <div id="validationFormCheck1Feedback" class="invalid-feedback">Example invalid feedback text</div>
</div>
</div>
</div>
<div class="form-group">
<label class="form-label">Radio</label>
<div class="form-field">
- <input type="radio" class="radio is-invalid" id="validationFormCheck2" name="radio-stacked" required>
+ <input type="radio" class="radio is-invalid" id="validationFormCheck2" name="radio-stacked" required aria-describedby="validationFormRadioFeedback">
<label for="validationFormCheck2">Toggle this radio</label>
</div>
<div class="form-field">
- <input type="radio" class="radio is-invalid" id="validationFormCheck3" name="radio-stacked" required>
+ <input type="radio" class="radio is-invalid" id="validationFormCheck3" name="radio-stacked" required aria-describedby="validationFormRadioFeedback">
<div class="form-field-content">
<label for="validationFormCheck3">Or toggle this other radio</label>
- <div class="invalid-feedback">More example invalid feedback text</div>
+ <div id="validationFormRadioFeedback" class="invalid-feedback">More example invalid feedback text</div>
</div>
</div>
</div>
<label class="form-label">Switch</label>
<div class="form-field">
<div class="switch">
- <input type="checkbox" id="validationFormSwitch" role="switch" switch class="is-invalid">
+ <input type="checkbox" id="validationFormSwitch" role="switch" switch class="is-invalid" aria-describedby="validationFormSwitchFeedback">
</div>
<div class="form-field-content">
<label for="validationFormSwitch">Toggle this switch</label>
- <div class="invalid-feedback">Example invalid switch feedback</div>
+ <div id="validationFormSwitchFeedback" class="invalid-feedback">Example invalid switch feedback</div>
</div>
</div>
</div>
<div class="form-field">
<label for="validationSelect" class="form-label">Select</label>
- <select class="form-control is-invalid" id="validationSelect" required>
+ <select class="form-control is-invalid" id="validationSelect" required aria-describedby="validationSelectFeedback">
<option value="">Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
- <div class="invalid-feedback">Example invalid select feedback</div>
+ <div id="validationSelectFeedback" class="invalid-feedback">Example invalid select feedback</div>
</div>
<div class="form-field">
<label for="validationFile" class="form-label">File input</label>
- <input type="file" class="form-control is-invalid" id="validationFile" required>
- <div class="invalid-feedback">Example invalid form file feedback</div>
+ <input type="file" class="form-control is-invalid" id="validationFile" required aria-describedby="validationFileFeedback">
+ <div id="validationFileFeedback" class="invalid-feedback">Example invalid form file feedback</div>
</div>
<div class="form-field">
<label for="validationRange" class="form-label">Range</label>
- <input type="range" class="form-range is-invalid" id="validationRange" min="0" max="5" required>
- <div class="invalid-feedback">Example invalid range feedback</div>
+ <input type="range" class="form-range is-invalid" id="validationRange" min="0" max="5" required aria-describedby="validationRangeFeedback">
+ <div id="validationRangeFeedback" class="invalid-feedback">Example invalid range feedback</div>
</div>
<div class="form-field">
<div class="form-floating">
- <input type="email" class="form-control is-invalid" id="validationFloating" placeholder="name@example.com" value="test@example.com">
+ <input type="email" class="form-control is-invalid" id="validationFloating" placeholder="name@example.com" value="test@example.com" aria-describedby="validationFloatingFeedback">
<label for="validationFloating">Email address</label>
</div>
- <div class="invalid-feedback d-block">Example invalid floating label feedback</div>
+ <div id="validationFloatingFeedback" class="invalid-feedback d-block">Example invalid floating label feedback</div>
</div>
<div class="form-field">
<div class="form-adorn-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/></svg>
</div>
- <input type="text" class="form-ghost" id="validationAdorn" placeholder="Search...">
+ <input type="text" class="form-ghost" id="validationAdorn" placeholder="Search..." aria-describedby="validationAdornFeedback">
</div>
- <div class="invalid-feedback">Example invalid adorned input feedback</div>
+ <div id="validationAdornFeedback" class="invalid-feedback">Example invalid adorned input feedback</div>
</div>
<div class="form-field">
<label for="validationInputGroup" class="form-label">Input group</label>
<div class="input-group">
<span class="input-group-text">@</span>
- <input type="text" class="form-control is-invalid" id="validationInputGroup" placeholder="Username">
+ <input type="text" class="form-control is-invalid" id="validationInputGroup" placeholder="Username" aria-describedby="validationInputGroupFeedback">
</div>
- <div class="invalid-feedback">Please choose a username</div>
+ <div id="validationInputGroupFeedback" class="invalid-feedback">Please choose a username</div>
</div>
<div class="form-field">
<label class="form-label" for="validationChipInput">Tags</label>
<div class="chip-input">
<span class="chip">Example</span>
- <input type="text" class="form-ghost is-invalid" id="validationChipInput" placeholder="Add tag...">
+ <input type="text" class="form-ghost is-invalid" id="validationChipInput" placeholder="Add tag..." aria-describedby="validationChipInputFeedback">
</div>
- <div class="invalid-feedback">Please add at least one tag</div>
+ <div id="validationChipInputFeedback" class="invalid-feedback">Please add at least one tag</div>
</div>
</form>`} />
<div class="grid gap-5">
<div class="form-field md:g-col-6">
<label for="validationTooltip01" class="form-label">Name</label>
- <input type="text" class="form-control" id="validationTooltip01" value="Mark Otto" required>
- <div class="tooltip invalid-tooltip">Full name is required</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationTooltip01" value="Mark Otto" required aria-describedby="validationTooltip01Feedback">
+ <div id="validationTooltip01Feedback" class="tooltip invalid-tooltip">Full name is required</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-6">
<label for="validationTooltipDonation" class="form-label">Donation amount</label>
<div class="input-group">
<span class="input-group-text" id="inputGroupTooltipPrepend">$</span>
- <input type="number" class="form-control" value="100" id="validationTooltipDonation" aria-describedby="inputGroupTooltipPrepend" required>
+ <input type="number" class="form-control" value="100" id="validationTooltipDonation" aria-describedby="inputGroupTooltipPrepend validationTooltipDonationFeedback" required>
</div>
- <div class="tooltip invalid-tooltip">Please enter a donation amount</div><!-- [!code highlight] -->
+ <div id="validationTooltipDonationFeedback" class="tooltip invalid-tooltip">Please enter a donation amount</div><!-- [!code highlight] -->
</div>
</div>
<div class="form-field">
<label for="validationTooltipAddress" class="form-label">Address</label>
- <input type="text" class="form-control" id="validationTooltipAddress" value="1234 Main St" required>
- <div class="tooltip invalid-tooltip">Please enter a mailing address</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationTooltipAddress" value="1234 Main St" required aria-describedby="validationTooltipAddressFeedback">
+ <div id="validationTooltipAddressFeedback" class="tooltip invalid-tooltip">Please enter a mailing address</div><!-- [!code highlight] -->
</div>
<div class="grid gap-5">
<div class="form-field md:g-col-6">
<label for="validationTooltip03" class="form-label">City</label>
- <input type="text" class="form-control" id="validationTooltip03" required>
- <div class="tooltip invalid-tooltip">Please provide a city</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationTooltip03" required aria-describedby="validationTooltip03Feedback">
+ <div id="validationTooltip03Feedback" class="tooltip invalid-tooltip">Please provide a city</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-4">
<label for="validationTooltip04" class="form-label">State</label>
- <select class="form-control" id="validationTooltip04" required>
+ <select class="form-control" id="validationTooltip04" required aria-describedby="validationTooltip04Feedback">
<option selected disabled value="">Choose…</option>
<option>...</option>
</select>
- <div class="tooltip invalid-tooltip">Please select a state</div><!-- [!code highlight] -->
+ <div id="validationTooltip04Feedback" class="tooltip invalid-tooltip">Please select a state</div><!-- [!code highlight] -->
</div>
<div class="form-field md:g-col-2">
<label for="validationTooltip05" class="form-label">Zip</label>
- <input type="text" class="form-control" id="validationTooltip05" required>
- <div class="tooltip invalid-tooltip">Required</div><!-- [!code highlight] -->
+ <input type="text" class="form-control" id="validationTooltip05" required aria-describedby="validationTooltip05Feedback">
+ <div id="validationTooltip05Feedback" class="tooltip invalid-tooltip">Required</div><!-- [!code highlight] -->
</div>
</div>