Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 55 additions & 53 deletions site/src/content/docs/forms/validation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,49 +31,51 @@ For custom Bootstrap form validation messages, add `data-bs-validate` and the `n

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>

Expand Down Expand Up @@ -189,9 +191,9 @@ For invalid fields, ensure that the invalid feedback/error message is associated
<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>
Expand All @@ -206,9 +208,9 @@ For invalid fields, ensure that the invalid feedback/error message is associated

<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">
Expand Down Expand Up @@ -279,8 +281,8 @@ Validation styles are available for the following form controls and components:
<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>
Expand All @@ -289,30 +291,30 @@ Validation styles are available for the following form controls and components:
<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'/>
</svg>
</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>
Expand All @@ -321,44 +323,44 @@ Validation styles are available for the following form controls and components:
<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">
Expand All @@ -367,27 +369,27 @@ Validation styles are available for the following form controls and components:
<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>`} />

Expand All @@ -403,43 +405,43 @@ This example functions the same as the [custom styles example](#custom-styles).
<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>

Expand Down
Loading
Loading