Forms

Examples and usage guidelines for form control styles, layout options, and custom components for creating a wide variety of forms.

Overview

Figuration's form controls expand on the Rebooted form styles with classes. Use these classes to opt into their customized displays for a more consistent rendering across browsers and devices.

Be sure to use an appropriate type attribute on all inputs (e.g., email for email address or number for numerical information) to take advantage of newer input controls like email verification, number selection, and more.

Alternatives to Hidden Labels

Assistive technologies such as screen readers will have trouble with your forms if you don't include a label for every input. For these inline forms, you can hide the labels using the .sr-only class. There are further alternative methods of providing a label for assistive technologies, such as the aria-label, aria-labelledby or title attribute. If none of these are present, assistive technologies may resort to using the placeholder attribute, if present, but note that use of placeholder as a replacement for other labelling methods is not advised.

Text Inputs

Textual form controls—like <input>s, <select>s, and <textarea>s—are styled with the .form-control class. Included are styles for general appearance, focus state, sizing, and more.

<div class="form-group">
<label for="example-input">Example text input</label>
<input type="text" class="form-control" id="example-input" placeholder="Input text here">
</div>
<div class="form-group">
<label for="example-select-1">Example select</label>
<select class="form-control" id="example-select-1">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label for="example-select-2">Example multiple select</label>
<select multiple class="form-control" id="example-select-2">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label for="example-texarea">Example textarea</label>
<textarea class="form-control" id="example-texarea" rows="3"></textarea>
</div>

Control Sizing

By default, .form-control uses em units for sizing so that they will scale with their explicit font-size.

You can also set heights and font-sizes using component sizing classes, such as:

  • .form-control-xsmall
  • .form-control-small
  • .form-control-large
  • .form-control-xlarge
<input class="form-control form-control-xlarge" type="text" placeholder="Extra large form control" aria-label=".form-control-xlarge size example">
<input class="form-control form-control-large" type="text" placeholder="Large form control" aria-label=".form-control-large size example">
<input class="form-control" type="text" placeholder="Default form control" aria-label="default size example">
<input class="form-control form-control-small" type="text" placeholder="Small form control" aria-label=".form-control-small size example">
<input class="form-control form-control-xsmall mb-2" type="text" placeholder="Extra small form control" aria-label=".form-control-xsmall size example">
<input class="form-control fs-large" type="text" placeholder="Explicit large font size" aria-label=".fs-large size example">
<input class="form-control fs-small" type="text" placeholder="Explicit small font size" aria-label=".fs-small size example">

The sizing classes also work on other inputs such as <select>s and <textarea>s.

<select class="form-control form-control-xlarge">
<option>Extra large select</option>
</select>
<select class="form-control form-control-large">
<option>Large select</option>
</select>
<select class="form-control">
<option>Default select</option>
</select>
<select class="form-control form-control-small">
<option>Small select</option>
</select>
<select class="form-control form-control-xsmall">
<option>Extra small select</option>
</select>

Readonly Inputs

Add the readonly boolean attribute on an input to prevent modification of the input's value. Read-only inputs appear lighter (just like disabled inputs), but retain the standard cursor.

<input class="form-control" type="text" placeholder="Readonly input" aria-label="Readonly input example" readonly>

Static Inputs

When you want to have readonly fields in your form styled as plain text, use the .form-control-static class to remove the default form field styling and preserve the correct margin and padding.

<div class="form-group row">
<label for="static-email" class="col-sm-2 form-label">Email</label>
<div class="col-sm-10">
<input type="text" readonly class="form-control-static" id="static-email" value="email@example.com">
</div>
</div>
<div class="form-group row">
<label for="static-password" class="col-sm-2 form-label">Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="static-password" placeholder="Password">
</div>
</div>
<form class="form-inline">
<div class="form-group me-0_5">
<label for="inputEmail2" class="sr-only">Email</label>
<input type="text" readonly class="form-control-static" id="inputEmail2" value="email@example.com">
</div>
<div class="form-group me-0_5">
<label for="inputPassword2" class="sr-only">Password</label>
<input type="password" class="form-control" id="inputPassword2" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Confirm identity</button>
</form>

Label, Legend, and Static Sizing

Just like sizing the form inputs, you can size <label>s, <legends>, and static controls with:

  • .form-label-xsmall
  • .form-label-small
  • .form-label-large
  • .form-label-xlarge
<div class="form-group flex-items-center row">
<label class="col-sm-2 form-label form-label-xsmall" for="labelstatic-1">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control-static form-label-xsmall" id="labelstatic-1" value="email@example.com">
</div>
</div>
<div class="form-group flex-items-center row">
<label class="col-sm-2 form-label form-label-small" for="labelstatic-2">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control-static form-label-small" id="labelstatic-2" value="email@example.com">
</div>
</div>
<div class="form-group flex-items-center row">
<label class="col-sm-2 form-label" for="labelstatic-3">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control-static" id="labelstatic-3" value="email@example.com">
</div>
</div>
<div class="form-group flex-items-center row">
<label class="col-sm-2 form-label form-label-large" for="labelstatic-4">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control-static form-label-large" id="labelstatic-4" value="email@example.com">
</div>
</div>
<div class="form-group flex-items-center row">
<label class="col-sm-2 form-label form-label-xlarge" for="labelstatic-5">Email</label>
<div class="col-sm-10">
<input type="text" class="form-control-static form-label-xlarge" id="labelstatic-5" value="email@example.com">
</div>
</div>

Disabled States

Add the disabled attribute on an input to prevent user interactions and make it appear lighter in color.

<input class="form-control" id="disabled-input" type="text" placeholder="Disabled input" aria-label="Disabled input example" disabled>

Add the disabled attribute to a <fieldset> to disable all the controls within.

<form>
<fieldset disabled aria-label="Disabled fieldset example">
<div class="form-group">
<label for="disabled-text">Disabled input</label>
<input type="text" id="disabled-text" class="form-control" placeholder="Disabled input">
</div>
<div class="form-group">
<label for="disabled-select">Disabled select menu</label>
<select id="disabled-select" class="form-control">
<option>Disabled select</option>
</select>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="disabled-check">
<label class="form-check-label" for="disabled-check">Can't check this</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</fieldset>
</form>

Caveat About Link Functionality of <a>

By default, browsers will treat all native form controls (<input>, <select> and <button> elements) inside a <fieldset disabled> as disabled, preventing both keyboard and mouse interactions on them.

However, if your form also includes <a ... class="btn btn-*"> elements, these will only be given a style of pointer-events: none. As noted in the accessibility section about disabled anchors, you must manually modify these controls by adding tabindex="-1" to prevent them from receiving focus and aria-disabled="disabled" to signal their state to assistive technologies.

Cross-browser Compatibility

While Figuration will apply these styles in all browsers, Internet Explorer 11 and below don't fully support the disabled attribute on a <fieldset>. Use custom JavaScript to disable the fieldset in these browsers.

Help Text

Block-level help text in forms can be created using .form-text. Inline help text can be flexibly implemented using any inline HTML element and utility classes like .text-muted.

Associating Help Text With Form Controls

Help text should be explicitly associated with the form control it relates to using the aria-describedby attribute. This will ensure that assistive technologies—such as screen readers—will announce this help text when the user focuses or enters the control.

Help text below inputs can be styled with .form-text. This class includes display: block; and adds some top margin for easy spacing from the inputs above.

Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.
<label for="help-pass">Password</label>
<input type="password" id="help-pass" class="form-control" aria-describedby="help-pass-text">
<div id="help-pass-text" class="form-text">
Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.
</div>

Inline text can use any typical inline HTML element (be it a <span>, <small>, or something else), optionally using utility classes.

Must be 8-20 characters long.
<div class="form-inline">
<div class="form-group">
<label for="inline-pass" class="me-0_5">Password</label>
<input type="password" id="inline-pass" class="form-control me-0_5" aria-describedby="inline-pass-text">
<small id="inline-pass-text" class="text-muted">
Must be 8-20 characters long.
</small>
</div>
</div>

Checkboxes and Radios

Default checkboxes and radios are improved upon with the help of .form-check, a single class for both input types that improves the layout and behavior of their HTML elements. Checkboxes are for selecting one or several options in a list, while radios are for selecting one option from many.

Disabled checkboxes and radios are supported by using the disabled attribute on the <input>, or by being inside a disabled <fieldset>, and will lighten the text color of a sibling .form-check-label to help indicate the input's state.

The .form-check container has a padding-left so that the siblings of the <input> (such as <label>, help text, or validation feedback) are easily aligned.

By default, any number of checkboxes and radios that are immediate sibling will be vertically stacked and appropriately spaced with .form-check.

Some additional help text could appear right here.
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="default-checkbox-1">
<label class="form-check-label" for="default-checkbox-1">Default checkbox</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="default-checkbox-2">
<label class="form-check-label" for="default-checkbox-2">Default checkbox</label>
<small class="text-muted d-block">Some additional help text could appear right here.</small>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="default-checkbox-3" disabled>
<label class="form-check-label" for="default-checkbox-3">Disabled checkbox</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="default-radio" value="" id="default-radio-1">
<label class="form-check-label" for="default-radio-1">First default radio</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="default-radio" value="" id="default-radio-2">
<label class="form-check-label" for="default-radio-2">Second default radio</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="default-radio" value="" id="default-radio-3" disabled>
<label class="form-check-label" for="default-radio-3">Disabled radio</label>
</div>

Custom Style

For even more customization and cross browser consistency, use our stylized form elements to replace the browser defaults.

Add the .form-checkradio modifier class to a .form-check to enable the stylized inputs. The visual treatment is determined from the type attribute on the <input>.

We hide the default <input> with opacity and use a <label> element with .form-check-label to build the stylized indicator in its place with ::before and ::after. Unfortunately we can't build a custom one from just the <input> because CSS does not support content, appearance in IE 11, or pseudo-elements on that element.

We also use the sibling selector (~) and the <input> states—like :checked—to style the form indicator and <label> text for each item.

Stylized checkboxes can also utilize the :indeterminate pseudo class when manually set via JavaScript (there is no available HTML attribute for specifying it).

In the checked and indeterminate states, we use icons from Open Iconic. This provides us the best control for styling and positioning across browsers and devices.

Some additional help text could appear right here.
Indeterminate checkboxes must be toggled via JavaScript—there's no HTML attribute for this.
Disabled fieldset
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check0" checked>
<label class="form-check-label" for="check0">Custom checkbox</label>
<small class="text-muted d-block">Some additional help text could appear right here.</small>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check1">
<label class="form-check-label" for="check1">Indeterminate custom checkbox</label>
<small class="text-muted d-block">Indeterminate checkboxes must be toggled via JavaScript—there's no HTML attribute for this.</small>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check2">
<label class="form-check-label" for="check2">Custom checkbox with a really long label to see what layout becomes when the text content wraps to the next line, but this needs a large amount of text to make sure the wrapping occurs.</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check3" disabled>
<label class="form-check-label" for="check3">Disabled custom checkbox</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check4" disabled checked>
<label class="form-check-label" for="check4">Disabled checked custom checkbox</label>
</div>
<fieldset class="mt-1" disabled>
<legend class="form-label">Disabled fieldset</legend>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check5">
<label class="form-check-label" for="check5">Custom checkbox in a disabled fieldset</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="check6" checked>
<label class="form-check-label" for="check6">Checked custom checkbox in a disabled fieldset</label>
</div>
</fieldset>
Disabled fieldset
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio0" name="radios" checked>
<label class="form-check-label" for="radio0">Custom radio</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio1" name="radios">
<label class="form-check-label" for="radio1">Custom radio</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio2" name="radios" disabled>
<label class="form-check-label" for="radio2">Disabled custom radio</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio3" name="radiosdis" disabled checked>
<label class="form-check-label" for="radio3">Disabled checked custom radio</label>
</div>
<fieldset class="mt-1" disabled>
<legend class="form-label">Disabled fieldset</legend>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio4" name="radiosfsdisfs">
<label class="form-check-label" for="radio4">Custom radio in a disabled fieldset</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="radio5" name="radiosfsdisfs" checked>
<label class="form-check-label" for="radio5">Checked custom radio in a disabled fieldset</label>
</div>
</fieldset>

For the indeterminate checkbox above we are using the following script:

document.getElementById("check1").indeterminate = true;

Switch

In similar fashion to the stylized checkbox and radio input, transform either of the input types to a stylized toggle switch by the using the .form-switch modifier class instead.

Some additional help text could appear right here.
Some additional help text could appear right here.
Some additional help text could appear right here.
Disabled fieldset
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="switch0">
<label class="form-check-label" for="switch0">Custom switch checkbox</label>
<small class="text-muted d-block">Some additional help text could appear right here.</small>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="switch1" disabled>
<label class="form-check-label" for="switch1">Disabled custom switch checkbox</label>
<small class="text-muted d-block">Some additional help text could appear right here.</small>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="switch2" disabled checked>
<label class="form-check-label" for="switch2">Disabled checked custom switch checkbox</label>
<small class="text-muted d-block">Some additional help text could appear right here.</small>
</div>
<fieldset class="mt-1" disabled>
<legend class="form-label">Disabled fieldset</legend>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="switch3">
<label class="form-check-label" for="switch3">Custom switch checkbox in a disabled fieldset</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="switch4" checked>
<label class="form-check-label" for="switch4">Checked switch checkbox in a disabled fieldset</label>
</div>
</fieldset>
Disabled fieldset
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradio0" name="switchradio" checked>
<label class="form-check-label" for="switchradio0">Custom switch radio</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradio1" name="switchradio">
<label class="form-check-label" for="switchradio1">Custom switch radio</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradiods0" name="switchradiods" disabled checked>
<label class="form-check-label" for="switchradiods0">Disabled checked custom switch radio</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradiods1" name="switchradiods" disabled>
<label class="form-check-label" for="switchradiods1">Disabled custom switch radio</label>
</div>
<fieldset class="mt-1" disabled>
<legend class="form-label">Disabled fieldset</legend>
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradiofs0" name="switchradiofs" checked>
<label class="form-check-label" for="switchradiofs0">Custom switch radio in a disabled fieldset</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="radio" id="switchradiofs1" name="switchradiofs">
<label class="form-check-label" for="switchradiofs1">Custom switch radio in a disabled fieldset</label>
</div>
</fieldset>

Without Labels

You can use .form-check without labels, but you will still need to provide some form of label for assistive technologies (for instance, using aria-label).

However, the stylized inputs will need to keep their label in order for the visual input to appear.

<div class="form-check">
<input class="form-check-input" type="checkbox" id="nolabel0" value="" aria-label="...">
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="nolabel-radio" id="nolabel-1" value="" aria-label="...">
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="nolabel2" value="">
<label class="form-check-label" for="nolabel2">
<span class="sr-only">Visually hidden label text</span>
</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="nolabel3" value="">
<label class="form-check-label" for="nolabel3">
<span class="sr-only">Visually hidden label text</span>
</label>
</div>

External Labels

Label can be supplied outside of the .form-check container also.

<div class="row">
<label class="col-md-auto" for="extlabel0">External label</label>
<div class="col">
<div class="form-check form">
<input class="form-check-input" type="checkbox" id="extlabel0" checked>
<label class="form-check-label" for="extlabel0"></label>
</div>
</div>
</div>
<div class="row">
<label class="col-md-auto" for="extlabel1">External label</label>
<div class="col">
<div class="form-check form-checkradio">
<input class="form-check-input" type="checkbox" id="extlabel1" checked>
<label class="form-check-label" for="extlabel1"></label>
</div>
</div>
</div>
<div class="row">
<label class="col-md-auto" for="extlabel2">External label</label>
<div class="col">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="extlabel2" checked>
<label class="form-check-label" for="extlabel2"></label>
</div>
</div>
</div>

Inline

Group checkboxes or radios on the same horizontal row by using display and margin utility classes, such as .d-inline-block and .me-1.

<div class="form-check d-inline-block me-1">
<input class="form-check-input" type="checkbox" id="inline0" checked>
<label class="form-check-label" for="inline0">Inline checkbox</label>
</div>
<div class="form-check form-checkradio d-inline-block me-1">
<input class="form-check-input" type="checkbox" id="inline1" checked>
<label class="form-check-label" for="inline1">Inline custom checkbox</label>
</div>
<div class="form-check form-checkradio d-inline-block me-1">
<input class="form-check-input" type="radio" id="inline2" checked>
<label class="form-check-label" for="inline2">Inline custom radio</label>
</div>
<div class="form-check form-switch d-inline-block">
<input class="form-check-input" type="checkbox" id="inline3" checked>
<label class="form-check-label" for="inline3">Inline custom switch</label>
</div>

Sizing

Our custom checkbox, radio, and switch inputs use em for sizing, so that they will scale with their explicit or inherited font-size.

<div class="form-check form-checkradio fs-xlarge">
<input class="form-check-input" type="checkbox" id="resize0" checked>
<label class="form-check-label" for="resize0">Resized custom checkbox</label>
</div>
<div class="form-check form-checkradio">
<input class="form-check-input" type="radio" id="resize1" checked>
<label class="form-check-label fs-large" for="resize1">Resized custom radio</label>
</div>
<div class="fs-small">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="resize2" checked>
<label class="form-check-label" for="resize2">Resized custom switch</label>
</div>
</div>

You can also set a font-size on the .form-check container, then reset font-size of content inside the <label>.

<div class="form-check form-checkradio fs-xlarge">
<input class="form-check-input" type="checkbox" id="resizealt0" checked>
<label class="form-check-label" for="resize0"><span class="fs-base">Resized custom checkbox</span></label>
</div>

File Browser

Using .form-file as a wrapper, we hide the default file <input> via opacity and instead style the <label> with some additional child elements to recreate the filename text and button portions of the input. A width and height are also set on the <input> for proper spacing for surrounding content.

The file input requires additional JavaScript if you would like to have a functional Choose file... and selected file name text.

<div class="form-file">
<input type="file" class="form-file-input" id="formFile">
<label class="form-file-label" for="formFile">
<span class="form-file-text">Choose file...</span>
<span class="form-file-button">Browse</span>
</label>
</div>

Longer filename text is truncated and an ellipsis is added when there's not enough space.

<div class="form-file">
<input type="file" class="form-file-input" id="formFileLong">
<label class="form-file-label" for="formFileLong">
<span class="form-file-text">Lorem ipsum posuere consectetur est at lobortis nulla vitae elit libero a pharetra augue fusce dapibus tellus ac cursus commodo tortor mauris condimentum nibh ut fermentum massa justo sit amet risus cras mattis consectetur purus sit amet fermentum</span>
<span class="form-file-button">Browse</span>
</label>
</div>

Sizing

Use .form-file-* sizing modifiers to adjust the file input to match the textual inputs.

<div class="form-file form-file-xsmall mb-1">
<input type="file" class="form-file-input" id="formFileSize0">
<label class="form-file-label" for="formFileSize0">
<span class="form-file-text">Extra small choose file...</span>
<span class="form-file-button">Browse</span>
</label>
</div>
<div class="form-file form-file-small mb-1">
<input type="file" class="form-file-input" id="formFileSize1">
<label class="form-file-label" for="formFileSize1">
<span class="form-file-text">Small choose file...</span>
<span class="form-file-button">Browse</span>
</label>
</div>
<div class="form-file form-file-large mb-1">
<input type="file" class="form-file-input" id="formFileSize2">
<label class="form-file-label" for="formFileSize2">
<span class="form-file-text">Large choose file...</span>
<span class="form-file-button">Browse</span>
</label>
</div>
<div class="form-file form-file-xlarge">
<input type="file" class="form-file-input" id="formFileSize3">
<label class="form-file-label" for="formFileSize3">
<span class="form-file-text">Extra large choose file...</span>
<span class="form-file-button">Browse</span>
</label>
</div>

Range

Create custom <input type="range"> controls with .form-range. The track (the background) and thumb (the value) are both styled to appear the same across browsers. As only IE and Firefox support "filling" their track from the left or right of the thumb as a means to visually indicate progress, we do not currently support it. We also hide the tooltip provided only by IE to maintain cross-browser consistency.

<label for="customRange1">Example range</label>
<input type="range" class="form-range" id="customRange1">

Range inputs have implicit values for min and max0 and 100, respectively. You may specify new values for those using the min and max attributes.

<label for="customRange2">Example range</label>
<input type="range" class="form-range" min="0" max="5" id="customRange2">

By default, range inputs "snap" to integer values. To change this, you can specify a step value. In the example below, we double the number of steps by using step="0.5".

<label for="customRange3">Example range</label>
<input type="range" class="form-range" min="0" max="5" step="0.5" id="customRange3">

Color Picker

<input type="color"> element need only a custom class, .form-color to trigger the custom styles.

Browser Compatibility

While Figuration supports styling <input type="color"> elements, some browsers don't. Use custom JavaScript to handle it in these browsers. For support details, see Can I Use.

<label for="customColor">Example color</label>
<input class="form-color" type="color" value="#117dba" id="customColor">

Layout

Since Figuration applies display: block and width: 100% to almost all our form controls, forms will by default stack vertically. Additional classes can be used to vary this layout on a per-form basis.

Form Groups

The .form-group class is the easiest way to add some structure to forms. It provides a flexible class that encourages proper grouping of labels, controls, optional help text, and form validation messaging. By default it only applies margin-bottom, but it picks up additional styles in .form-inline as needed. Use it with <fieldset>s, <div>s, or nearly any other element.

<div class="form-group">
<label class="form-label" for="formGroupExampleInput">Example label</label>
<input type="text" class="form-control" id="formGroupExampleInput" placeholder="Example input">
</div>
<div class="form-group">
<label class="form-label" for="formGroupExampleInput2">Another label</label>
<input type="text" class="form-control" id="formGroupExampleInput2" placeholder="Another input">
</div>

Form Grid

More complex forms can be built using our grid classes. Use these for form layouts that require multiple columns, varied widths, and additional alignment options.

Grid-based form layouts also support control sizing.

<div class="row">
<div class="col">
<label for="formGridExampleInput">First Name</label>
<input type="text" class="form-control" id="formGridExampleInput" placeholder="First name">
</div>
<div class="col">
<label for="formGridExampleInput2">Last Name</label>
<input type="text" class="form-control" id="formGridExampleInput2" placeholder="Last name">
</div>
</div>

Form Row

You may also swap .row for .form-row, a variation of our standard grid row that overrides the default column gutters for tighter and more compact layouts.

<div class="form-row">
<div class="col">
<input type="text" class="form-control" placeholder="First name" aria-label="First name">
</div>
<div class="col">
<input type="text" class="form-control" placeholder="Last name" aria-label="Last name">
</div>
</div>

More complex layouts can also be created with the grid system.

<form>
<div class="form-row">
<div class="form-group col-md-6">
<label for="grid-email">Email</label>
<input type="email" class="form-control" id="grid-email" placeholder="Email">
</div>
<div class="form-group col-md-6">
<label for="grid-pass">Password</label>
<input type="password" class="form-control" id="grid-pass" placeholder="Password">
</div>
</div>
<div class="form-group">
<label for="grid-address-1">Address</label>
<input type="text" class="form-control" id="grid-address-1" placeholder="1234 Main St">
</div>
<div class="form-group">
<label for="grid-address-2">Address 2</label>
<input type="text" class="form-control" id="grid-address-2" placeholder="Apartment, studio, or floor">
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="grid-city">City</label>
<input type="text" class="form-control" id="grid-city">
</div>
<div class="form-group col-md-4">
<label for="grid-state">State</label>
<select id="grid-state" class="form-control">
<option selected>Choose...</option>
<option>...</option>
</select>
</div>
<div class="form-group col-md-2">
<label for="grid-zip">Zip</label>
<input type="text" class="form-control" id="grid-zip">
</div>
</div>
<div class="form-group form-check">
<input class="form-check-input" type="checkbox" id="grid-check">
<label class="form-check-label" for="grid-check">
Check me out
</label>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>

Horizontal Form

Create horizontal forms with the grid by adding the .row class to form groups and using the .col-*-* classes to specify the width of your labels and controls. Be sure to add .form-label to your <label>s as well so they're vertically centered with their associated form controls.

At times, you maybe need to use margin or padding utilities to create that perfect alignment you need. For example, we've removed the padding-top on our stacked radio inputs label to better align the text baseline.

Radios
Checkbox
<form>
<div class="form-group row">
<label for="hform-email" class="col-sm-2 form-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="hform-email" placeholder="Email">
</div>
</div>
<div class="form-group row">
<label for="hform-pass" class="col-sm-2 form-label">Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="hform-pass" placeholder="Password">
</div>
</div>
<fieldset class="form-group">
<div class="row">
<legend class="form-label col-sm-2 pt-0">Radios</legend>
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="radio" name="hform-radio" id="gridRadios1" value="option1" checked>
<label class="form-check-label" for="gridRadios1">
First radio
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="hform-radio" id="hform-radio-2" value="option2">
<label class="form-check-label" for="hform-radio-2">
Second radio
</label>
</div>
<div class="form-check disabled">
<input class="form-check-input" type="radio" name="hform-radio" id="hform-radio-3" value="option3" disabled>
<label class="form-check-label" for="hform-radio-3">
Third disabled radio
</label>
</div>
</div>
</div>
</fieldset>
<div class="form-group row">
<div class="col-sm-2">Checkbox</div>
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hform-check">
<label class="form-check-label" for="hform-check">
Example checkbox
</label>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-10 offset-sm-2">
<button type="submit" class="btn btn-primary">Sign in</button>
</div>
</div>
</form>

Column Sizing

As shown in the previous examples, our grid system allows you to place any number of .cols within a .row. They will split the available width equally between them. You may also pick a subset of your columns to take up more or less space, while the remaining .cols equally split the rest, with specific column classes like .col-7.

<div class="form-row">
<div class="col-7">
<input type="text" class="form-control" placeholder="City" aria-label="City">
</div>
<div class="col">
<input type="text" class="form-control" placeholder="State" aria-label="State">
</div>
<div class="col">
<input type="text" class="form-control" placeholder="Zip" aria-label="Zip">
</div>
</div>

Auto-sizing

The example below uses a flexbox utility to vertically center the contents and changes .col to .col-auto so that your columns only take up as much space as needed. Put another way, the column sizes itself based on the contents.

@
<form>
<div class="form-row flex-items-center">
<div class="col-auto mb-0_5">
<label class="sr-only" for="autosize-name">Name</label>
<input type="text" class="form-control" id="autosize-name" placeholder="Jane Doe">
</div>
<div class="col-auto mb-0_5">
<label class="sr-only" for="autosize-user">Username</label>
<div class="input-group">
<div class="input-group-text">@</div>
<input type="text" class="form-control" id="autosize-user" placeholder="Username">
</div>
</div>
<div class="col-auto mb-0_25">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="autosize-check">
<label class="form-check-label" for="autosize-check">Remember me</label>
</div>
</div>
<div class="col-auto mb-0_5">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>

Here is the same form, but this time using specified column widths

@
<form>
<div class="form-row flex-items-center">
<div class="col-sm-3 mb-0_5">
<label class="sr-only" for="specsize-name">Name</label>
<input type="text" class="form-control" id="specsize-name" placeholder="Jane Doe">
</div>
<div class="col-sm-3 mb-0_5">
<label class="sr-only" for="specsize-user">Username</label>
<div class="input-group">
<div class="input-group-text">@</div>
<input type="text" class="form-control" id="specsize-user" placeholder="Username">
</div>
</div>
<div class="col-auto mb-0_25">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="specsize-check">
<label class="form-check-label" for="specsize-check">Remember me</label>
</div>
</div>
<div class="col-auto mb-0_5">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
<form>
<div class="form-row flex-items-center">
<div class="col mb-0_5">
<label class="sr-only" for="form-select">Preference</label>
<select class="form-control" id="form-select">
<option selected>Choose...</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
<div class="col-auto mb-0_25">
<div class="form-check form-checkradio">
<input type="checkbox" class="form-check-input" id="customize-check">
<label class="form-check-label" for="customize-check">Remember my preference</label>
</div>
</div>
<div class="col-auto mb-0_5">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>

Inline Forms

Use the .form-inline class to display a series of labels, form controls, and buttons on a single horizontal row. Form controls within inline forms vary slightly from their default states.

  • Controls are display: flex, collapsing any HTML white space and allowing you to provide alignment control with spacing and flexbox utilities.
  • Controls and input groups receive width: auto to override the Figuration default width: 100%.
  • Controls only appear inline in viewports that are at least 36em/576px wide to account for narrow viewports on mobile devices.

You may need to manually address the width and alignment of individual form controls with spacing utilities (as shown below). Lastly, as shown below, you should always include a <label> with each form control, even if you need to hide it from non-screenreader users with .sr-only.

@
<form class="form-inline">
<label class="sr-only" for="inline-name">Name</label>
<input type="text" class="form-control mb-0_5 me-sm-0_5" id="inline-name" placeholder="Jane Doe">

<label class="sr-only" for="inline-user">Username</label>
<div class="input-group mb-0_5 me-sm-0_5">
<div class="input-group-text">@</div>
<input type="text" class="form-control" id="inline-user" placeholder="Username">
</div>

<div class="form-check mb-0_5 me-sm-0_5">
<input class="form-check-input" type="checkbox" id="inline-checkbox-4">
<label class="form-check-label" for="inline-checkbox-4">Remember me</label>
</div>

<button type="submit" class="btn btn-primary mb-0_5">Submit</button>
</form>

Custom form controls and selects are also supported.

<form class="form-inline">
<label class="mb-0_5 me-0_5" for="inlineFormSelectPref">Preference</label>
<select class="form-control mb-0_5 me-sm-0_5" id="inlineFormSelectPref">
<option selected>Choose...</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>

<div class="form-check form-checkradio mb-0_5 me-sm-0_5">
<input type="checkbox" class="form-check-input" id="customControlInline">
<label class="form-check-label" for="customControlInline">Remember my preference</label>
</div>

<button type="submit" class="btn btn-primary mb-0_5">Submit</button>
</form>

Validation

Provide valuable, actionable feedback to your users with HTML5 form validation–available in all our supported browsers. Choose from the browser default validation feedback, or implement custom messages with our built-in classes and starter JavaScript.

We are aware that currently the client-side custom validation styles and tooltips are not accessible, since they are not exposed to assistive technologies. While we work on a solution, we'd recommend either using the server-side option or the default browser validation method.

How It Works

Here's how form validation works:

  • HTML form validation is applied via CSS's two pseudo-classes, :invalid and :valid. It applies to <input>, <select>, and <textarea> elements.
  • The :invalid and :valid styles are scoped to a parent .was-validated class, usually applied to the <form>. Otherwise, any required field without a value shows up as invalid on page load. This way, you may choose when to activate them (typically after form submission is attempted).
  • To reset the appearance of the form (for instance, in the case of dynamic form submissions using AJAX), remove the .was-validated class from the <form> again after submission.
  • As a fallback, .is-invalid and .is-valid classes may be used instead of the pseudo-classes for server side validation. They do not require a .was-validated parent class.
  • Due to constraints in how CSS works, we cannot (at present) apply styles to a <label> that comes before a form control in the DOM without the help of custom JavaScript.
  • All modern browsers support the constraint validation API, a series of JavaScript methods for validating form controls.
  • Feedback messages may utilize the browser defaults (different for each browser, and unstylable via CSS) or our custom feedback styles with additional HTML and CSS.
  • You may provide custom validity messages with setCustomValidity in JavaScript.

With that in mind, consider the following demos for our custom form validation styles, optional server side classes, and browser defaults.

Custom Styles

For custom form validation messages, you'll need to add the novalidate boolean attribute to your <form>. This disables the browser default feedback tooltips, but still provides access to the form validation APIs in JavaScript. Try to submit the form below; our JavaScript will intercept the submit button and relay feedback to you.

When attempting to submit, you'll see the :invalid and :valid styles applied to the form controls.

Custom feedback styles apply custom colors, borders, focus styles, feedback messages, and optional background icons to better communicate feedback.

Looks good!
Looks good!
@
Please choose a username.
Please provide a valid city.
Please provide a valid state.
Please provide a valid zip.
You must agree before submitting.
<form class="needs-validation" novalidate>
<div class="form-row">
<div class="col-md-4 mb-1">
<label for="validate-custom-1">First name</label>
<input type="text" class="form-control" id="validate-custom-1" placeholder="First name" value="John" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-custom-2">Last name</label>
<input type="text" class="form-control" id="validate-custom-2" placeholder="Last name" value="Smith" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-custom-3">Username</label>
<div class="input-group">
<span class="input-group-text" id="validate-custom-4">@</span>
<input type="text" class="form-control input-group-end" id="validate-custom-3" placeholder="Username" aria-describedby="validate-custom-4" required>
<div class="invalid-feedback">Please choose a username.</div>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-1">
<label for="validate-custom-5">City</label>
<input type="text" class="form-control" id="validate-custom-5" placeholder="City" required>
<div class="invalid-feedback">Please provide a valid city.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-custom-6">State</label>
<input type="text" class="form-control" id="validate-custom-6" placeholder="State" required>
<div class="invalid-feedback">Please provide a valid state.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-custom-7">Zip</label>
<input type="text" class="form-control" id="validate-custom-7" placeholder="Zip" required>
<div class="invalid-feedback">Please provide a valid zip.</div>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="validate-custom-8" required>
<label class="form-check-label" for="validate-custom-8">Agree to terms and conditions</label>
<div class="invalid-feedback">You must agree before submitting.</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>

<script>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(function() {
'use strict';
window.addEventListener('load', function() {
// Fetch all the forms we want to apply custom validation styles to
var forms = document.getElementsByClassName('needs-validation');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();
</script>

Browser Defaults

Not interested in custom validation feedback messages or writing JavaScript to change form behaviors? All good, you can use the browser defaults. Try submitting the form below. Depending on your browser and OS, you'll see a slightly different style of feedback.

While these feedback styles cannot be styled with CSS, you can still customize the feedback text through JavaScript.

@
<form>
<div class="form-row">
<div class="col-md-4 mb-1">
<label for="validate-browser-1">First name</label>
<input type="text" class="form-control" id="validate-browser-1" placeholder="First name" value="John" required>
</div>
<div class="col-md-4 mb-1">
<label for="validate-browser-2">Last name</label>
<input type="text" class="form-control" id="validate-browser-2" placeholder="Last name" value="Smith" required>
</div>
<div class="col-md-4 mb-1">
<label for="validate-browser-3">Username</label>
<div class="input-group">
<span class="input-group-text" id="validate-browser-4">@</span>
<input type="text" class="form-control input-group-end" id="validate-browser-3" placeholder="Username" aria-describedby="validate-browser-4" required>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-1">
<label for="validate-browser-5">City</label>
<input type="text" class="form-control" id="validate-browser-5" placeholder="City" required>
</div>
<div class="col-md-3 mb-1">
<label for="validate-browser-6">State</label>
<input type="text" class="form-control" id="validate-browser-6" placeholder="State" required>
</div>
<div class="col-md-3 mb-1">
<label for="validate-browser-7">Zip</label>
<input type="text" class="form-control" id="validate-browser-7" placeholder="Zip" required>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="validate-browser-8" required>
<label class="form-check-label" for="validate-browser-8">Agree to terms and conditions</label>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>

Server Side

When using server side validation you can indicate invalid and valid form fields with .is-invalid and .is-valid. Note that .invalid-feedback is also supported with these classes.

For invalid fields, ensure that the invalid feedback/error message is associated with the relevant form field using aria-describedby (noting that this attribute allows more than one id to be referenced, in case the field already points to additional form text).

Looks good!
Looks good!
@
Please choose a username.
Please provide a valid city.
Please provide a valid state.
Please provide a valid zip.
You must agree before submitting.
<form>
<div class="form-row">
<div class="col-md-4 mb-1">
<label for="validate-server-1">First name</label>
<input type="text" class="form-control is-valid" id="validate-server-1" placeholder="First name" value="John" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-server-2">Last name</label>
<input type="text" class="form-control is-valid" id="validate-server-2" placeholder="Last name" value="Smith" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-server-3">Username</label>
<div class="input-group">
<span class="input-group-text" id="validate-server-4">@</span>
<input type="text" class="form-control input-group-end is-invalid" id="validate-server-3" placeholder="Username" aria-describedby="validate-server-4 validate-server-4-fb" required>
<div id="validate-server-4-fb" class="invalid-feedback">Please choose a username.</div>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-1">
<label for="validate-server-5">City</label>
<input type="text" class="form-control is-invalid" id="validate-server-5" placeholder="City" aria-describedby="validate-server-5-fb" required>
<div id="validate-server-5-fb" class="invalid-feedback">Please provide a valid city.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-server-6">State</label>
<input type="text" class="form-control is-invalid" id="validate-server-6" placeholder="State" aria-describedby="validate-server-6-fb" required>
<div id="validate-server-6-fb" class="invalid-feedback">Please provide a valid state.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-server-7">Zip</label>
<input type="text" class="form-control is-invalid" id="validate-server-7" placeholder="Zip" aria-describedby="validate-server-7-fb" required>
<div id="validate-server-7-fb" class="invalid-feedback">Please provide a valid zip.</div>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input is-invalid" type="checkbox" value="" id="validate-server-8" aria-describedby="validate-server-8-fb" required>
<label class="form-check-label" for="validate-server-8">Agree to terms and conditions</label>
<div id="validate-server-8-fb" class="invalid-feedback">You must agree before submitting.</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>

Supported Elements

Validation styles are supported for the following form controls and components:

  • <input>s, <textarea>s, and <select>s using .form-control (only supports one .form-control in input groups)
  • .form-checks with either native of custom variants
  • .form-file
Please enter a message in the textarea.
Example invalid feedback text
More example invalid feedback text
Example invalid feedback text
More example invalid feedback text
Example invalid feedback text
Example invalid custom select feedback
Example invalid custom file feedback
@
Please choose a unique and valid username.
<form class="was-validated">
<div class="mb-1">
<label for="validate-textarea">Textarea</label>
<textarea class="form-control" id="validate-textarea" rows="3" placeholder="Required example textarea" required></textarea>
<div class="invalid-feedback">Please enter a message in the textarea.</div>
</div>

<div class="form-check mb-1">
<input type="checkbox" class="form-check-input" id="validate-support-1" required>
<label class="form-check-label" for="validate-support-1">Check this native checkbox</label>
<div class="invalid-feedback">Example invalid feedback text</div>
</div>

<div class="form-check">
<input type="radio" class="form-check-input" id="validate-support-2" name="radio-stacked0" required>
<label class="form-check-label" for="validate-support-2">Toggle this native radio</label>
</div>
<div class="form-check mb-1">
<input type="radio" class="form-check-input" id="validate-support-3" name="radio-stacked0" required>
<label class="form-check-label" for="validate-support-3">Or toggle this other native radio</label>
<div class="invalid-feedback">More example invalid feedback text</div>
</div>

<div class="form-check form-checkradio mb-1">
<input type="checkbox" class="form-check-input" id="validate-support-4" required>
<label class="form-check-label" for="validate-support-4">Check this custom checkbox</label>
<div class="invalid-feedback">Example invalid feedback text</div>
</div>

<div class="form-check form-checkradio">
<input type="radio" class="form-check-input" id="validate-support-5" name="radio-stacked1" required>
<label class="form-check-label" for="validate-support-5">Toggle this custom radio</label>
</div>
<div class="form-check form-checkradio mb-1">
<input type="radio" class="form-check-input" id="validate-support-6" name="radio-stacked1" required>
<label class="form-check-label" for="validate-support-6">Or toggle this other custom radio</label>
<div class="invalid-feedback">More example invalid feedback text</div>
</div>

<div class="form-check form-switch mb-1">
<input type="checkbox" class="form-check-input" id="validate-support-7" required>
<label class="form-check-label" for="validate-support-7">Check this custom checkbox</label>
<div class="invalid-feedback">Example invalid feedback text</div>
</div>

<div class="form-group">
<select class="form-control" aria-label="Select example" required>
<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 custom select feedback</div>
</div>

<div class="form-group mb-1">
<div class="form-file">
<input type="file" class="form-file-input" id="validatedCustomFile" required>
<label class="form-file-label" for="validatedCustomFile">
<span class="form-file-text">Choose file...</span>
<span class="form-file-button">Browse</span>
</label>
<div class="invalid-feedback">Example invalid custom file feedback</div>
</div>
</div>

<div class="input-group mb-1">
<span class="input-group-text" id="validate-support-ig">@</span>
<input type="text" class="form-control input-group-end" placeholder="Username" aria-label="Username" aria-describedby="validate-support-ig" required>
<div class="invalid-feedback">Please choose a unique and valid username.</div>
</div>

<button class="btn btn-primary" type="submit" disabled>Submit form</button>
</form>

Tooltips

If your form layout allows it, you can swap the .{valid|invalid}-feedback classes for .{valid|invalid}-tooltip classes to display validation feedback in a styled tooltip. Be sure to have a parent with position: relative on it for tooltip positioning. In the example below, our column classes have this already, but your project may require an alternative setup.

Looks good!
Looks good!
@
Please choose a unique and valid username.
Please provide a valid city.
Please provide a valid state.
Please provide a valid zip.
<form class="needs-validation" novalidate>
<div class="form-row">
<div class="col-md-4 mb-1">
<label for="validate-tooltip-1">First name</label>
<input type="text" class="form-control" id="validate-tooltip-1" placeholder="First name" value="John" required>
<div class="valid-tooltip">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-tooltip-2">Last name</label>
<input type="text" class="form-control" id="validate-tooltip-2" placeholder="Last name" value="Smith" required>
<div class="valid-tooltip">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-tooltip-3">Username</label>
<div class="input-group">
<span class="input-group-text" id="validate-tooltip-4">@</span>
<input type="text" class="form-control input-group-end" id="validate-tooltip-3" placeholder="Username" aria-describedby="validate-tooltip-4" required>
<div class="invalid-tooltip">Please choose a unique and valid username.</div>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-1">
<label for="validate-tooltip-5">City</label>
<input type="text" class="form-control" id="validate-tooltip-5" placeholder="City" required>
<div class="invalid-tooltip">Please provide a valid city.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-tooltip-6">State</label>
<input type="text" class="form-control" id="validate-tooltip-6" placeholder="State" required>
<div class="invalid-tooltip">Please provide a valid state.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-tooltip-7">Zip</label>
<input type="text" class="form-control" id="validate-tooltip-7" placeholder="Zip" required>
<div class="invalid-tooltip">Please provide a valid zip.</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>

Icons

Optional visual icon representations of the validation state can be added to textual <input class="form-control">, <textarea class="form-control">, and <select class="form-control"> elements by adding a .has-validation-icon class.

  • Validation icons are url()s configured via Sass variables that are applied to background-image rules for each state.
  • You may use your own base64 PNGs or SVGs by updating the Sass variables and recompiling.
  • Icons can also be disabled entirely by setting the $enable-form-validation-icon variable to false in the Sass.
Looks good!
Looks good!
@
Please choose a unique and valid username.
Please provide a valid city.
Please provide a valid state.
Please provide a valid zip.
Example invalid custom select feedback
Example invalid custom select feedback
Please enter a message in the textarea.
<form class="was-validated">
<div class="form-row">
<div class="col-md-4 mb-1">
<label for="validate-icon-1">First name</label>
<input type="text" class="form-control has-validation-icon" id="validate-icon-1" placeholder="First name" value="John" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-icon-2">Last name</label>
<input type="text" class="form-control has-validation-icon" id="validate-icon-2" placeholder="Last name" value="Smith" required>
<div class="valid-feedback">Looks good!</div>
</div>
<div class="col-md-4 mb-1">
<label for="validate-icon-3">Username</label>
<div class="input-group">
<span class="input-group-text" id="validate-icon-4">@</span>
<input type="text" class="form-control has-validation-icon input-group-end" id="validate-icon-3" placeholder="Username" aria-describedby="validate-icon-4" required>
<div class="invalid-feedback">Please choose a unique and valid username.</div>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-1">
<label for="validate-icon-5">City</label>
<input type="text" class="form-control has-validation-icon" id="validate-icon-5" placeholder="City" required>
<div class="invalid-feedback">Please provide a valid city.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-icon-6">State</label>
<input type="text" class="form-control has-validation-icon" id="validate-icon-6" placeholder="State" required>
<div class="invalid-feedback">Please provide a valid state.</div>
</div>
<div class="col-md-3 mb-1">
<label for="validate-icon-7">Zip</label>
<input type="text" class="form-control has-validation-icon" id="validate-icon-7" placeholder="Zip" required>
<div class="invalid-feedback">Please provide a valid zip.</div>
</div>
</div>
<div class="form-group">
<label for="validate-icon-8">Options</label>
<select class="form-control has-validation-icon" id="validate-icon-8" required>
<option value="">Choose one...</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<div class="invalid-feedback">Example invalid custom select feedback</div>
</div>
<div class="form-group">
<label for="validate-icon-9">Options</label>
<select class="form-control has-validation-icon" id="validate-icon-9" size="4" required>
<option value="">Choose one...</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<div class="invalid-feedback">Example invalid custom select feedback</div>
</div>
<div class="form-group">
<label for="validate-icon-10">Textarea</label>
<textarea class="form-control has-validation-icon" id="validate-icon-10" rows="3" placeholder="Required example textarea" required></textarea>
<div class="invalid-feedback">Please enter a message in the textarea.</div>
</div>
<button class="btn btn-primary" type="submit" disabled>Submit form</button>
</form>

Customizing

Validation states can be customized via Sass with the $form-validation-states map. Located in our _settings.scss file, this Sass map is looped over to generate the default valid/invalid validation states. Included is a nested map for customizing each state's color and icon. While no other states are supported by browsers, those using custom styles can easily add more complex form feedback.

Please note that we do not recommend customizing these values without also modifying the form-validation-state mixin.

// Sass map from `_settings.scss`
// Override this and recompile your Sass to generate different states
$form-validation-states:
"valid": (
"color": $form-feedback-valid-color,
"icon": $form-feedback-icon-valid-image
),
"invalid": (
"color": $form-feedback-invalid-color,
"icon": $form-feedback-icon-invalid-image
)
);

// Loop from `_forms.scss`
// Any modifications to the above Sass map will be reflected in your compiled
// CSS via this loop.
@each $state, $data in $form-validation-states {
@include form-validation-state($state, map-get($data, color), map-get($data, icon));
}

Accessibility

Ensure that all form controls have an appropriate accessible name so that their purpose can be conveyed to users of assistive technologies. The simplest way to achieve this is to use a <label> element, or—in the case of buttons—to include sufficiently descriptive text as part of the <button>...</button> content.

For situations where it's not possible to include a visible <label> or appropriate text content, there are alternative ways of still providing an accessible name, such as:

  • <label> elements hidden using the .sr-only class
  • Pointing to an existing element that can act as a label using aria-labelledby
  • Providing a title attribute
  • Explicitly setting the accessible name on an element using aria-label

If none of these are present, assistive technologies may resort to using the placeholder attribute as a fallback for the accessible name on <input> and <textarea> elements. The examples in this section provide a few suggested, case-specific approaches.

While using visually hidden content (.sr-only, aria-label, and even placeholder content, which disappears once a form field has content) will benefit assistive technology users, a lack of visible label text may still be problematic for certain users. Some form of visible label is generally the best approach, both for accessibility and usability.

SASS Reference

Variables

The available Customization options, or Sass variables, that can be customized for forms.

Name Type Default Description
$enable-form boolean true Enable the generation of the form classes. Smaller segements of the form classes can be disabled with the following $enable-* variables.
$enable-form-control boolean true Enable the generation of the textual form control rules.
$enable-form-control-sizing boolean true Enable the generation of the sizing classes for form controls.
$enable-form-control-static boolean true Enable the generation of the static form control class.
$enable-form-label boolean true Enable the generation of the form control label class.
$enable-form-label-sizing boolean true Enable the generation of the sizing classes for form control labels.
$enable-form-text boolean true Enable the generation of the form text class.
$enable-form-check boolean true Enable the generation of the stacking layout for checkbox and radio inputs.
$enable-form-check-checkradio boolean true Enable the generation of the custom styles for checkbox and radio inputs.
$enable-form-check-switch boolean true Enable the generation of the custom switch styles for checkbox and radio inputs.
$enable-form-file boolean true Enable the generation of the classes for custom file inputs.
$enable-form-file-sizing boolean true Enable the generation of the sizing classes for custom file inputs.
$enable-form-range boolean true Enable the generation of the classes for custom range inputs.
$enable-form-color boolean true Enable the generation of the classes for custom color inputs.
$enable-form-group boolean true Enable the generation of the form group classes.
$enable-form-row boolean true Enable the generation of the form row classes.
$enable-form-inline boolean true Enable the generation of the inline form classes.
$enable-form-validation boolean true Enable the generation of the form validation classes.
$enable-form-validation-feeback boolean true Enable the generation of the form validation text feedback classes.
$enable-form-validation-tooltip boolean true Enable the generation of the form validation tooltip classes.
$enable-form-validation-icon boolean true Enable the generation of the form validation icon class.
$input-font-family string null Base input font family.
$input-font-size string $btn-font-size Base input font size.
$input-font-weight string $font-weight-normal Base input font weight.
$input-line-height string $btn-line-height Base input line height.
$input-padding-y string $btn-padding-y Base input vertical padding.
$input-padding-x string $btn-padding-x Base input horizontal padding.
$input-sizes string $component-sizes Input size variants.
$input-bg string $white Input background color for inactive state.
$input-color string $uibase-700 Input text color for inactive state.
$input-border-color string $uibase-200 Input border color for inactive state.
$input-border-width string $border-width Base input border-width.
$input-border-radius string $border-radius Base input border-radius.
$input-box-shadow string map-get($shadows, "i1") Input inner box shadow for inactive state.
$input-focus-bg string $input-bg Input background color for focus state.
$input-focus-color string $input-color Input text color for focus state.
$input-focus-border-color string palette($primary, 300) Input border color for focus state.
$input-focus-box-shadow-size string 0 0 0 .1875rem Input box shadow dimensions for focus state.
$input-focus-box-shadow-alpha float .35 Input box shadow alpha, opacity, value for focus state.
$input-focus-box-shadow string $input-focus-box-shadow-size rgba($component-active-bg, $input-focus-box-shadow-alpha) Input box shadow for focus state.
$input-disabled-bg string $uibase-50 Input background color for disabled state.
$input-disabled-color string $component-disabled-color Input text color for disabled state.
$input-disabled-border-color string null Border color for disabled state.
$input-disabled-opacity string 1 Opacity value for disabled state.
$input-placeholder-color string #999 Input placheholder text color.
$input-static-color string $body-color Text color for static readonly inputs.
$form-label-font-weight string $font-weight-normal Font weight for .form-label.
$form-text-margin-top string .25rem Vertical spacing between input and support text.
$form-text-font-size string .$small-font-size Font size for support text.
$form-text-font-style string null Font style for support text.
$form-text-font-weight string null Font weight for support text.
$form-text-color string $text-muted Color for support text.
$form-group-margin-bottom string 1rem Vertical spacing for form group.
$form-row-gutter-width string .625rem Gutter spacing for form row.
$form-inline-breakpoint breakpoint sm Breakpoint where inline froms switch from vertical to horizontal layout.
$form-inline-check-margin-x string .25rem Horizontal spacing for form check when inline.
$form-check-gutter string 1.25rem Reserved spacing width for default inputs within .form-check.
$form-check-margin-bottom string .3125rem Vertical adjustment for inputs within .form-check.
$form-check-label-color string null Text color for `.form-check-label`.
$form-check-label-font-weight string null Font weight for `.form-check-label`.
$form-check-label-cursor string null Pointer cursor for `.form-check-label`.
$form-check-label-disabled-opacity string .6 Opacity for `.form-check-label` when the input is disabled.
$form-checkradio-size string 1em Height and width for custom styled checkbox and radio inputs.
$form-checkradio-gutter string calc(#{$form-checkradio-size} + .375em) Reserved spacing width for custom styled checkbox and radio inputs.
$form-checkradio-bg string $white Background color for custom styled checkbox and radio inputs in inactive state.
$form-checkradio-border-width string $border-width Border width for custom styled checkbox and radio inputs
$form-checkradio-border-color string $uibase-300 Border color for custom styled checkbox and radio inputs in inactive state.
$form-checkradio-box-shadow string map-get($shadows, "i1") Box shadow for custom styled checkbox and radio inputs in inactive state.
$form-checkradio-icon-size string calc(#{$form-checkradio-size} - .375em) Height and width of the background image icon for custom styled checkbox and radio input.
$form-checkradio-focus-border-color string $input-border-color Border color for custom styled checkbox and radio inputs in focused state.
$form-checkradio-focus-box-shadow string $input-focus-box-shadow Box shadow for custom styled checkbox and radio inputs in focused state.
$form-checkradio-checked-bg string $primary Background color for custom styled checkbox and radio inputs in checked state.
$form-checkradio-checked-color string $white Icon color for custom styled checkbox and radio inputs in checked state.
$form-checkradio-checked-border-color string $primary Border color for custom styled checkbox and radio inputs in checked state.
$form-checkradio-checked-box-shadow string map-get($shadows, "i1") Box shadow for custom styled checkbox and radio inputs in checked state.
$form-checkradio-checkbox-border-radius string $border-radius Border radius for custom styled checkbox inputs.
$form-checkradio-checkbox-icon string encode-svg(url("data:image/svg+xml,")) Icon for custom styled checkbox inputs when in checked state.
$form-checkradio-radio-border-radius string 50% Border radius for custom styled radio inputs.
$form-checkradio-radio-icon string encode-svg(url("data:image/svg+xml,")) Icon for custom styled radio inputs when in checked state.
$form-checkradio-indeterminate-bg string $primary Background color for custom styled checkbox inputs when in indeterminate state.
$form-checkradio-indeterminate-border-color string $form-checkradio-indeterminate-bg Border color for custom styled checkbox inputs when in indeterminate state.
$form-checkradio-indeterminate-icon string encode-svg(url("data:image/svg+xml,")) Icon for custom styled checkbox inputs when in indeterminate state.
$form-switch-width string 1.75em Width for custom styled switch inputs.
$form-switch-gutter string calc(#{$form-switch-width} + .375em) Reserved spacing width for custom styled checkbox and radio inputs.
$form-switch-track-height string 1em Height for track of custom styled switch inputs.
$form-switch-track-bg string $white Background color for track of custom styled switch inputs in inactive state.
$form-switch-track-border-width string $input-border-width Border width for track of custom styled switch inputs.
$form-switch-track-border-color string $uibase-300 Border color for track of custom styled switch inputs in inactive state.
$form-switch-track-border-radius string $white Border radius for track of custom styled switch inputs.
$form-switch-track-box-shadow string map-get($shadows, "i1") Box shadow for track of custom styled switch inputs.
$form-switch-track-focus-bg string null Background color for track of custom styled switch inputs in focused state.
$form-switch-track-focus-border-color string $input-focus-border-color Border color for track of custom styled switch inputs in focused state.
$form-switch-track-focus-box-shadow string $input-focus-box-shadow Box shadow for track of custom styled switch inputs in focused state.
$form-switch-track-checked-bg string $primary Background color for track of custom styled switch inputs in checked state.
$form-switch-track-checked-border-color string $primary Border color for track of custom styled switch inputs in checked state.
$form-switch-track-checked-box-shadow string $form-switch-track-box-shadow Box shadow for track of custom styled switch inputs in checked state.
$form-switch-thumb-offset string calc(.25em - #{$form-switch-track-border-width}) Horizontal offset for thumb of custom styled switch inputs.
$form-switch-thumb-width string .625em Width for thumb of custom styled switch inputs.
$form-switch-thumb-height string .625em Height for thumb of custom styled switch inputs.
$form-switch-thumb-bg string $uibase-300 Background color for thumb of custom styled switch inputs in inactive state.
$form-switch-thumb-border-width string $border-width Border width for thumb of custom styled switch inputs.
$form-switch-thumb-border-color string $form-switch-thumb-bg Border color for thumb of custom styled switch inputs.
$form-switch-thumb-border-radius string 50% Border radius for thumb of custom styled switch inputs.
$form-switch-thumb-box-shadow string none Box shadow for thumb of custom styled switch inputs.
$form-switch-thumb-focus-bg string palette($primary, 300) Background color for thumb of custom styled switch inputs in focused state.
$form-switch-thumb-focus-border-color string $form-switch-thumb-focus-bg Border color for thumb of custom styled switch inputs in focused state.
$form-switch-thumb-focus-border-color string $form-switch-thumb-focus-bg Border color for thumb of custom styled switch inputs in focused state.
$form-switch-thumb-focus-box-shadow string null Box shadow for thumb of custom styled switch inputs in focused state.
$form-switch-thumb-checked-bg string $white Background color for thumb of custom styled switch inputs in checked state.
$form-switch-thumb-checked-border-color string $white Border color for thumb of custom styled switch inputs in checked state.
$form-switch-thumb-checked-box-shadow string null Box shadow for thumb of custom styled switch inputs in checked state.
$form-select-indicator-offset string .375rem Additional horizontal spacing of visual indicator for custom select input.
$form-select-indicator-width string .75em Width of visual indicator for custom select input.
$form-select-indicator-height string .75em Height of visual indicator for custom select input.
$form-select-indicator-color string .rgba($uibase-700, .85) Color of visual indicator for custom select input.
$form-select-indicator-image string encode-svg(url("data:image/svg+xml,")) Icon for visual indicator of custom select input.
$form-select-indicator-position string right $form-select-indicator-offset center Position for visual indicator of custom select input.
$form-file-button-color string $uibase-600 Button text color for file input.
$form-file-button-bg string $uibase-50 Button background color for file input.
$form-file-button-font-family string $btn-font-family Button font-family for file input.
$form-file-button-font-weight string $btn-font-weight Button font-weight for file input.
$form-file-button-disabled-color string $component-disabled-color Button text color for file input when in disabled state.
$form-file-button-disabled-bg string $uibase-50 Button background color for file input when in disabled state.
$form-file-button-disabled-opacity string 1 Button opacity for file input when in disabled state.
$form-range-track-height string .5em Height of track for custom range input.
$form-range-track-cursor string pointer Pointer style of track for custom range input.
$form-range-track-bg string $uibase-100 Background color of track for custom range input.
$form-range-track-border string 0 Border style of track for custom range input.
$form-range-track-border-radius string $form-range-track-height Border radius of track for custom range input.
$form-range-track-box-shadow string map-get($shadows, "i1") Box shadow of track for custom range input.
$form-range-thumb-width string 1.125em Width of thumb for custom range input.
$form-range-thumb-height string $form-range-thumb-width Height of thumb for custom range input.
$form-range-thumb-bg string $primary Background color of thumb for custom range input.
$form-range-thumb-border string 0 Border style of thumb for custom range input.
$form-range-thumb-border-radius string 50% Border radius of thumb for custom range input.
$form-range-thumb-box-shadow string map-get($shadows, "d1") Box shadow of thumb for custom range input.
$form-range-thumb-focus-box-shadow string $input-focus-box-shadow Box shadow of thumb for custom range input in focus state.
$form-range-thumb-focus-box-shadow-width string .1875rem Width of box shadow of thumb for custom range input in focus state.
$form-range-thumb-active-bg string palette($primary, 600) Background color of thumb for custom range input in active state.
$form-range-thumb-disabled-bg string $uibase-300 Background color of thumb for custom range input in disabled state.
$form-range-height string calc(#{$form-range-thumb-height} + (#{$form-range-thumb-focus-box-shadow-width} * 2)) Height of custom range input.
$form-range-min-width string 8rem

Minimum width of custom range input.

Note: Browser default seems to be 129px/~8rem for IE/Chrome/Safari

$form-feedback-margin-top string $form-text-margin-top Vertical spacing between input and feeback text.
$form-feedback-font-size string $form-text-font-size Font size for feedback text.
$form-feedback-valid-color string map-get($base-colors, "success") Base color for valid feedback state.
$form-feedback-invalid-color string map-get($base-colors, "danger") Base color for invalid feedback state.
$form-feedback-icon-offset string .25em Additional horizontal spacing of visual feedback indicator icon.
$form-feedback-icon-width string 1em Width of visual feedback indicator icon.
$form-feedback-icon-height string 1em Height of visual feedback indicator icon.
$form-feedback-icon-valid-color string $form-feedback-valid-color Icon color for valid feedback state.
$form-feedback-icon-valid-image string encode-svg(url("data:image/svg+xml,")) Icon for valid feedback state.
$form-feedback-icon-invalid-color string $form-feedback-invalid-color Icon color for invalid feedback state.
$form-feedback-icon-invalid-image string encode-svg(url("data:image/svg+xml,")) Icon for invalid feedback state.
$form-feedback-select-icon-position string right calc(#{$form-feedback-icon-offset} + #{$form-select-indicator-width} + #{$form-select-indicator-offset}) center Position of feedback icon for custom select inputs.
$input-transition string background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out Transition effect for inputs.
$switch-transition string all .15s ease-in-out Transition effect for custom switch inputs.

Mixins

Here are the mixins related to forms that we use to help generate our CSS. You can also uses these mixins to generate your own custom components or utilities.

form-validation-state()

Build form validation rules.

@include form-validation-state($state, $color, $icon);
Argument Type Default Description
$state string '' The value appended to generate the classes for the given validation state.
$color string none The color to mix and use throughout the validation state.
$icon string none The icon to use throughout the validation state.

form-control-focus()

Add the focus state to a form control or input.

@include form-control-focus();

form-range-track()

Add the common, cross-browser rules for track of a range input.

@include form-range-track();

form-range-thumb()

Add the common, cross-browser rules for thumb of a range input.

@include form-range-thumb();