Forms

Form field stack: .form-group wraps one field (label + control + help/error text) and provides vertical rhythm. Controls are subcomponents with their own roots: .form-control (inputs/textareas), .form-select, .form-check (checkbox/radio rows), and .toggle switches.

Root: .form-group on <div>, <fieldset>

Example

Example
Keep it short.
<div class="form-group"><label class="form-label" for="summary">Summary <span class="required">*</span></label><input class="form-control" id="summary" type="text" required><span class="form-text">Keep it short.</span></div>

Contract

Structure

SelectorRequiredDescription
.form-labeloptionalA <label class="form-label" for="..."> above the control; append <span class="required">*</span> for mandatory fields.
.form-textoptionalHelp text below the control.
.invalid-feedbackoptionalError text; pair with .is-invalid on the control.

Accessibility

OnAttributeLevelWhen
.form-labelforrecommendedAlways when the label is not wrapping its control — every control needs a programmatically associated label.

Associate every control with a label via for/id (the demo does this throughout). Mark invalid controls with .is-invalid AND aria-invalid="true", and link the .invalid-feedback text with aria-describedby. The .required asterisk is visual; also set the required attribute on the control.

Nesting

Allowed in:

  • <form>
  • .modal-body
  • .card-body
  • settings panels

Never inside (or containing):

  • .form-group

Subcomponents

Form-control

Text-style input skin for <input> and <textarea>. Textareas grow (min-height 80px, resize vertical). .form-control-subtle is invisible until hovered/focused (inline edit); .is-invalid shows the danger border.

Root: .form-control on <input>, <textarea>

Examples

Example 1
<input class="form-control" id="summary" type="text" placeholder="What needs doing?">
Example 2
<textarea class="form-control" id="desc"></textarea>

Variants & modifiers

ClassAxisRules
form-control-compactmodifieroptional
form-control-subtlemodifieroptional
is-invalidmodifieroptional

Accessibility

OnAttributeLevelWhen
.form-control.is-invalidaria-invalidrecommendedRecommended whenever .is-invalid is applied, together with aria-describedby pointing at the .invalid-feedback element.

Must have an associated <label> (for/id), or aria-label when a visible label is genuinely impossible. Placeholder text is not a label.

Nesting

Allowed in:

  • .form-group

Form-select

Native <select> skinned with a chevron. Same sizing/interaction states as .form-control.

Root: .form-select on <select>

Example

Example
<select class="form-select" id="type"><option>Story</option><option>Bug</option></select>

Accessibility

Must have an associated <label>. Prefer native select over custom dropdowns for form input — it is free keyboard/AT support.

Nesting

Allowed in:

  • .form-group

Form-check

One checkbox or radio row: an .form-check-input followed by its text <label>. Stack rows inside a .form-group; radios in one group share a name attribute.

Root: .form-check on <div>

Example

Example
<div class="form-check"><input class="form-check-input" type="checkbox" id="watch" checked><label for="watch">Notify watchers</label></div>

Structure

SelectorRequiredDescription
.form-check-inputrequiredAn <input type="checkbox"> or <input type="radio"> with class form-check-input (custom-drawn box/dot; 2px top margin aligns it with the label's first line).
labeloptionalText label with for pointing at the input's id. Not a CSS dependency, but a control without one has no accessible name.

Accessibility

Always pair the input with a label via for/id so the text is clickable and the control is named. The custom appearance keeps the native input element, so keyboard and AT behavior are native.

Nesting

Allowed in:

  • .form-group

Never inside (or containing):

  • .form-check

Toggle

iOS-style switch: a <label class="toggle"> wrapping a visually-hidden checkbox and a .toggle-slider span. The wrapping label makes the whole switch clickable; .toggle-lg is the larger size.

Root: .toggle on <label>

Example

Example
<label class="toggle"><input type="checkbox" aria-label="Send me updates" checked><span class="toggle-slider"></span></label>

Variants & modifiers

ClassAxisRules
toggle-lgmodifieroptional

Structure

SelectorRequiredDescription
inputrequiredA visually-hidden <input type="checkbox"> that must come IMMEDIATELY BEFORE .toggle-slider (the CSS drives the slider via input:checked + .toggle-slider).
.toggle-sliderrequiredThe drawn track/knob span, immediate next sibling of the input.

Accessibility

The wrapping <label> gives click-anywhere behavior, but the checkbox still needs a text name: put visible text inside the label, or aria-label on the input (the demo places adjacent text outside the label, which does NOT name the control).

Nesting

Allowed in:

  • .form-group
  • settings rows

Never inside (or containing):

  • .toggle