Validation
Use validation helpers with forms, inputs, selects, floating labels, checks, radios, and server-bound model expressions.
How it works
Bootstrap validation styles are scoped to form controls with :valid and :invalid, or to explicit is-valid and is-invalid classes. Add needs-validation and no-validate when JavaScript will manage custom validation, or add was-validated after a submit attempt to reveal browser constraint states.
BCL uses bs-validation-message for invalid feedback. It can be bound with map-to so MVC model-state errors can populate the message when no inner content is supplied. Server-side validation still needs the server to return the invalid state and feedback in the rendered form.
Validation examples use normal form events such as onsubmit because validation is browser-form behavior rather than a Bootstrap lifecycle plugin event. Bootstrap's JavaScript event model still applies to any plugin-backed controls nested inside the form.
Custom styles
This example mirrors Bootstrap's custom validation pattern with BCL form, grid, input, select, input group, check, and validation-message helpers. Add needs-validation and no-validate when custom JavaScript should manage the submit experience.
<bs-form needs-validation="true" no-validate="true" onsubmit="if (!this.checkValidity()) { event.preventDefault(); event.stopPropagation(); } this.classList.add('was-validated');">
<bs-row x-gutter="Default3" y-gutter="Default3">
<bs-div span-md="Four" position="Relative">
<bs-label>First name</bs-label>
<bs-input value="Mark" required="true" validation-state="Valid" />
<bs-validation-message feedback-type="Valid">Looks good!</bs-validation-message>
</bs-div>
<bs-div span-md="Four">
<bs-label>Last name</bs-label>
<bs-input value="Otto" required="true" validation-state="Valid" />
<bs-validation-message feedback-type="Valid">Looks good!</bs-validation-message>
</bs-div>
<bs-div span-md="Four">
<bs-label>Username</bs-label>
<bs-input-group>
<bs-input-group-text>@@</bs-input-group-text>
<bs-input required="true" validation-state="Invalid" />
<bs-validation-message>Choose a username.</bs-validation-message>
</bs-input-group>
</bs-div>
</bs-row>
<bs-row x-gutter="Default3" y-gutter="Default3" top-margin="Default3">
<bs-div span-md="Six">
<bs-label>City</bs-label>
<bs-input required="true" validation-state="Invalid" />
<bs-validation-message>Provide a valid city.</bs-validation-message>
</bs-div>
<bs-div span-md="Three">
<bs-label>State</bs-label>
<bs-select required="true" validation-state="Invalid">
<bs-option value="">Choose...</bs-option>
<bs-option value="TX">Texas</bs-option>
</bs-select>
<bs-validation-message>Select a valid state.</bs-validation-message>
</bs-div>
<bs-div span-md="Three">
<bs-label>Zip</bs-label>
<bs-input required="true" validation-state="Invalid" />
<bs-validation-message>Provide a valid zip.</bs-validation-message>
</bs-div>
</bs-row>
<bs-check validation-feedback="true" top-margin="Default3" bottom-margin="Default3">
<bs-input required="true" />
<bs-label>Agree to terms and conditions</bs-label>
<bs-validation-message>You must agree before submitting.</bs-validation-message>
</bs-check>
<bs-button btn-style="Primary" btn-type="Submit">Submit form</bs-button>
</bs-form>
Browser defaults
Omit no-validate when native browser validation bubbles are preferred. The same BCL controls can participate because required, type, pattern, min, max, and related attributes flow through to the rendered controls.
<bs-form>
<bs-div bottom-margin="Default3">
<bs-label>Email address</bs-label>
<bs-input input-type="Email" required="true" placeholder-text="name@example.com" />
</bs-div>
<bs-div bottom-margin="Default3">
<bs-label>Example select</bs-label>
<bs-select required="true">
<bs-option value="">Open this select menu</bs-option>
<bs-option value="1">One</bs-option>
</bs-select>
</bs-div>
<bs-button btn-style="Primary" btn-type="Submit">Submit form</bs-button>
</bs-form>
Server-side
Use was-validated on the form to display browser constraint validation state immediately. This is useful in server-rendered postback flows where the form has already been submitted and the page is returning validation feedback.
<bs-form was-validated="true">
<bs-floating-label bottom-margin="Default3">
<bs-input input-type="Email" placeholder-text="name@example.com" required="true" />
<bs-label>Email address</bs-label>
<bs-validation-message>Use a work email address.</bs-validation-message>
</bs-floating-label>
<bs-check validation-feedback="true" bottom-margin="Default3">
<bs-input required="true" />
<bs-label>Agree to terms</bs-label>
<bs-validation-message>You must agree before submitting.</bs-validation-message>
</bs-check>
<bs-button btn-style="Primary" btn-type="Submit">Submit form</bs-button>
</bs-form>
Supported elements
Validation styles are supported for text inputs, selects, textareas, checks, switches, and radio groups. For grouped controls, keep feedback inside the group helper when the helper exposes a validation slot so the message remains associated with the control.
<bs-form was-validated="true">
<bs-row x-gutter="Default3" y-gutter="Default3">
<bs-div span-md="Six">
<bs-label>Textarea</bs-label>
<bs-textarea required="true" rows="3"></bs-textarea>
<bs-validation-message>Enter a short message.</bs-validation-message>
</bs-div>
<bs-div span-md="Six">
<bs-radio-group>
<bs-legend>Radio group</bs-legend>
<bs-radio value="first" validation-feedback="true">
<bs-label>First option</bs-label>
<bs-validation-message>Select one option.</bs-validation-message>
</bs-radio>
<bs-radio value="second">
<bs-label>Second option</bs-label>
</bs-radio>
</bs-radio-group>
</bs-div>
</bs-row>
</bs-form>
Tooltips
Place validation tooltip feedback inside a positioned ancestor so Bootstrap can anchor the tooltip message to the field.
<bs-form was-validated="true">
<bs-row x-gutter="Default3" y-gutter="Default3">
<bs-div span-md="Four">
<bs-label>First name</bs-label>
<bs-input value="Mark" required="true" validation-state="Valid" />
<bs-validation-message feedback-type="Valid" tooltip="true">Looks good!</bs-validation-message>
</bs-div>
<bs-div span-md="Four" position="Relative">
<bs-label>Username</bs-label>
<bs-input-group>
<bs-input-group-text>@@</bs-input-group-text>
<bs-input required="true" validation-state="Invalid" />
<bs-validation-message feedback-type="Invalid" tooltip="true">Choose a username.</bs-validation-message>
</bs-input-group>
</bs-div>
<bs-div span-md="Four" position="Relative">
<bs-label>City</bs-label>
<bs-input required="true" validation-state="Invalid" />
<bs-validation-message feedback-type="Invalid" tooltip="true">Provide a valid city.</bs-validation-message>
</bs-div>
</bs-row>
</bs-form>
Server-bound validation
For MVC model binding, pass map-to on BCL controls and validation messages. bs-validation-message emits the validation binding attributes and can pull the first model-state error for the mapped field when the tag has no explicit content.
<bs-form method="post" was-validated="true">
<bs-row x-gutter="Default3" y-gutter="Default3">
<bs-div span-md="Six">
<bs-label>Server accepted field</bs-label>
<bs-input validation-state="Valid" value="Valid value" />
</bs-div>
<bs-div span-md="Six">
<bs-label>Server rejected field</bs-label>
<bs-input validation-state="Invalid" value="Rejected value" />
<bs-validation-message>Server rejected this value.</bs-validation-message>
</bs-div>
</bs-row>
<bs-div top-margin="Default3">
<bs-check validation-feedback="true">
<bs-input required="true" validation-state="Invalid" />
<bs-label>Accept policy</bs-label>
<bs-validation-message>The policy must be accepted.</bs-validation-message>
</bs-check>
</bs-div>
</bs-form>
CSS customization
Bootstrap exposes validation colors and icons through CSS variables and Sass variables. Prefer theme-level customization for colors, borders, and feedback icons so BCL helpers can continue rendering the same semantic form structure.
.was-validated .form-control:valid,
.form-control.is-valid {
border-color: var(--bs-form-valid-border-color);
}
.was-validated .form-control:invalid,
.form-control.is-invalid {
border-color: var(--bs-form-invalid-border-color);
}
Sass maps
Bootstrap validation state maps control the generated valid and invalid selectors, colors, icons, and feedback styles. Keep those changes at the Bootstrap theme layer so BCL validation helpers continue to render semantic form feedback.
$form-validation-states: (
"valid": (
"color": var(--#{$prefix}success),
"icon": $form-feedback-icon-valid
),
"invalid": (
"color": var(--#{$prefix}danger),
"icon": $form-feedback-icon-invalid
)
);