Validation

Validation states mark a field as valid or invalid and show a message under it, so the user sees what to fix.

Validation states

Validation states mark a field as valid or invalid, so the user sees which fields to correct and, for an invalid one, why.

To apply the validation state to the form control, use the .is-valid and .is-invalid classes. For assistive tech, also set aria-invalid="true" on invalid controls.

<div>
  <label class="form-label" for="state-valid">Valid state</label>
  <input type="text" id="state-valid" class="form-control is-valid" aria-invalid="false" />
</div>
<div>
  <label class="form-label" for="state-invalid">Invalid state</label>
  <input type="text" id="state-invalid" class="form-control is-invalid" aria-invalid="true" />
</div>

Validation feedback

To provide users with additional information about the validation state, you can use the .valid-feedback and .invalid-feedback classes. Link the message with aria-describedby when you can.

Please provide a valid city.
<div>
  <label class="form-label required" for="city-invalid">City</label>
  <input type="text" class="form-control is-invalid" id="city-invalid" required aria-invalid="true" aria-describedby="city-invalid-feedback" />
  <div class="invalid-feedback" id="city-invalid-feedback">Please provide a valid city.</div>
</div>

You can also use the .valid-feedback to provide users with positive feedback.

Looks good!
<div>
  <label class="form-label required" for="city-valid">City</label>
  <input type="text" class="form-control is-valid" id="city-valid" required value="Warsaw" aria-describedby="city-valid-feedback" />
  <div class="valid-feedback" id="city-valid-feedback">Looks good!</div>
</div>

Subtle validation states

For a quieter version, show a tick or a cross icon instead of the colored frame and the feedback message.

To do this, use the .is-valid-lite and .is-invalid-lite classes.

These variants drop the colored frame and the feedback message, so the state is left to a small icon. Keep aria-invalid on the field, and keep the reason in text somewhere the field points to - otherwise the error exists only as a symbol.

<div>
  <label class="form-label" for="state-valid-lite">Valid state</label>
  <input type="text" id="state-valid-lite" class="form-control is-valid is-valid-lite" aria-invalid="false" />
</div>
<div>
  <label class="form-label" for="state-invalid-lite">Invalid state</label>
  <input type="text" id="state-invalid-lite" class="form-control is-invalid is-invalid-lite" aria-invalid="true" />
</div>

Accessibility

  • Colour alone must not say that a field is wrong. Keep aria-invalid="true" on the field and a message in text.
  • Give the feedback element an id and point the field at it with aria-describedby, so the message is read with the field rather than after the form.
  • Say what to do, not only what failed. "Please provide a valid city" beats "Invalid".
  • On submit, move focus to the first field that failed. Otherwise a keyboard user has to hunt for it.
  • Validate when the user leaves a field, not on every keystroke. A message that appears and disappears while typing is announced over and over.

SCSS variables

Use these SCSS variables to customize form validation states. The default values are:

$form-validation-states: (
  'valid': (
    'color': var(--form-valid-color),
    'icon': $form-feedback-icon-valid,
    'tooltip-color': #fff,
    'tooltip-bg-color': var(--success),
    'focus-box-shadow': 0 0 $input-btn-focus-blur $input-focus-width color-mix(in srgb, var(--success) #{math.percentage($input-btn-focus-color-opacity)}, transparent),
    'border-color': var(--form-valid-border-color),
  ),
  'invalid': (
    'color': var(--form-invalid-color),
    'icon': $form-feedback-icon-invalid,
    'tooltip-color': #fff,
    'tooltip-bg-color': var(--danger),
    'focus-box-shadow': 0 0 $input-btn-focus-blur $input-focus-width color-mix(in srgb, var(--danger) #{math.percentage($input-btn-focus-color-opacity)}, transparent),
    'border-color': var(--form-invalid-border-color),
  ),
);

On this page

130 sleek illustrations for your startup's visual identity.