Skip to main content

Validation

Validation styles that follow Angular form state, native constraints or the server.

Bootstrap’s validation docs describe the markup and CSS.

Angular forms

Controls follow the state of their Angular form control. Once a control is touched, or after the form is submitted, invalid controls get .is-invalid and aria-invalid="true", and their bsInvalidFeedback is shown and joins their aria-describedby. Add bsValidate to the form so its controls also show errors after a submit, and so Bootstrap styles :user-invalid for controls without an Angular form control. Try submitting the form below.

Full name is required.
Please provide a city.
Enter 5 digits.
Shipping method
Arrives in 5-7 business days.
Arrives in 2-3 business days.
Please choose a shipping method.
You must agree before submitting.
<form class="row g-3 align-items-start" bsValidate [formGroup]="form" (ngSubmit)="save()">
  <div bsFormField class="md:col-4">
    <label bsFormLabel>Name</label>
    <input bsFormControl formControlName="name" autocomplete="name" />
    <div bsInvalidFeedback>Full name is required.</div>
  </div>
  <div bsFormField class="md:col-5">
    <label bsFormLabel>City</label>
    <input bsFormControl formControlName="city" autocomplete="address-level2" />
    <div bsInvalidFeedback>Please provide a city.</div>
  </div>
  <div bsFormField class="md:col-3">
    <label bsFormLabel>Zip</label>
    <input bsFormControl formControlName="zip" autocomplete="postal-code" />
    <div bsInvalidFeedback>Enter 5 digits.</div>
  </div>
  <fieldset class="form-group col-12">
    <legend class="form-label">Shipping method</legend>
    <div bsFormField class="mb-1">
      <input type="radio" bsRadio value="standard" formControlName="shipping" />
      <div class="form-field-content">
        <label bsLabel>Standard</label>
        <small bsFormText>Arrives in 5-7 business days.</small>
      </div>
    </div>
    <div bsFormField>
      <input type="radio" bsRadio value="express" formControlName="shipping" />
      <div class="form-field-content">
        <label bsLabel>Express</label>
        <small bsFormText>Arrives in 2-3 business days.</small>
        <div bsInvalidFeedback>Please choose a shipping method.</div>
      </div>
    </div>
  </fieldset>
  <div bsFormField class="col-12">
    <input type="checkbox" bsCheck formControlName="terms" />
    <div class="form-field-content">
      <label bsLabel>Agree to terms and conditions</label>
      <div bsInvalidFeedback>You must agree before submitting.</div>
    </div>
  </div>
  <div class="col-12 d-flex align-items-center gap-3">
    <button type="submit" bsButton theme="primary">Submit form</button>
    <span role="status">{{ message() }}</span>
  </div>
</form>

Success styles

Use bsValidate="valid" to also show success styles and bsValidFeedback on valid controls.

Please enter a valid email address.
Looks good!
<form bsValidate="valid">
  <div bsFormField>
    <label bsFormLabel>Email address</label>
    <input type="email" bsFormControl [formControl]="email" autocomplete="email" />
    <div bsInvalidFeedback>Please enter a valid email address.</div>
    <div bsValidFeedback>Looks good!</div>
  </div>
</form>

Native constraints

Without Angular forms, bsValidate uses the browser’s constraint validation: attributes such as required, type="email" or pattern. It sets novalidate to hide the browser’s tooltips, blocks the submission while a constraint fails, and sets the validation state after the user leaves a control or submits the form.

Please enter a valid email address.
HTML
<form class="vstack gap-3" bsValidate>
  <div bsFormField>
    <label bsFormLabel>Email address</label>
    <input type="email" bsFormControl required autocomplete="email" />
    <div bsInvalidFeedback>Please enter a valid email address.</div>
  </div>
  <button type="submit" bsButton theme="primary" class="align-self-start">Submit</button>
</form>

Server-side

Set validation to invalid or valid to show a state from the server. It overrides the automatic state until you set it back to auto.

That username is taken.
Looks good!
HTML
<div class="vstack gap-3">
  <div bsFormField>
    <label bsFormLabel>Username</label>
    <input bsFormControl validation="invalid" value="mark" autocomplete="username" />
    <div bsInvalidFeedback>That username is taken.</div>
  </div>
  <div bsFormField>
    <label bsFormLabel>Full name</label>
    <input bsFormControl validation="valid" value="Mark Otto" autocomplete="name" />
    <div bsValidFeedback>Looks good!</div>
  </div>
</div>

Tooltips

Add tooltip to feedback to show it as a tooltip below the control. The field needs position: relative. Tooltips don’t suit checkboxes, radios and switches.

Please provide a city.
<div bsFormField class="position-relative pb-5">
  <label bsFormLabel>City</label>
  <input bsFormControl [formControl]="city" autocomplete="address-level2" />
  <div bsInvalidFeedback tooltip>Please provide a city.</div>
</div>

API

BsValidate

Selector: form[bsValidate] · Exported as: bsValidate

Inputs

NameTypeDefaultDescription
bsValidate'' | 'valid'''valid also shows success styles on valid controls.

Methods

NameTypeDescription
submittedSignal<boolean>True after the user tried to submit the form, until it is reset.

BsInvalidFeedback

Selector: [bsInvalidFeedback]

Inputs

NameTypeDefaultDescription
tooltipbooleanfalseShows the feedback as a tooltip.
idstringgeneratedElement id. Generated when not set.

BsValidFeedback

Selector: [bsValidFeedback]

Inputs

NameTypeDefaultDescription
tooltipbooleanfalseShows the feedback as a tooltip.
idstringgeneratedElement id. Generated when not set.

BsControl

Selector: [bsControl] · Exported as: bsControl

Inputs

NameTypeDefaultDescription
idstringgeneratedElement id. Generated when not set, and used for the field’s label.
validation'auto' | 'valid' | 'invalid' | 'none''auto'Validation styles. auto follows the bound Angular form control.

Methods

NameTypeDescription
stateSignal<'valid' | 'invalid' | null>The validation state the control shows.