Skip to content

Forms ​

Bootstrap

Bootstrap form controls. Patterns below; usage → Rules.

Input ​

form-label + form-control. Optional form-text for hints.

Display as 12 Mar 2026
html
<label class="form-label" for="company-name">Company name</label>
<input
  class="form-control"
  id="company-name"
  type="text"
  placeholder="Van den Berg Logistics"
/>
<label class="form-label" for="due-date">Due date</label>
<input
  class="form-control"
  id="due-date"
  type="date"
  placeholder="12 Mar 2026"
/>
<div class="form-text">Display as 12 Mar 2026</div>

Input group ​

Prefix with input-group-text.

€
html
<label class="form-label" for="currency">Amount</label>
<div class="input-group">
  <span class="input-group-text">€</span>
  <input class="form-control" id="currency" type="text" placeholder="12.400" />
</div>

Sqrl custom

input-group-merge (not a Bootstrap class): type="text" + role="searchbox" (not type="search"), and bi-x-circle-fill to clear.

html
<label class="form-label" for="search-contacts">Search</label>
<div class="input-group input-group-merge">
  <span class="input-group-text"><i class="bi bi-search"></i></span>
  <input
    class="form-control"
    id="search-contacts"
    type="text"
    role="searchbox"
    autocomplete="off"
    placeholder="Search contacts"
    value="Marieke"
  />
  <button type="button" class="input-group-text" aria-label="Clear search">
    <i class="bi bi-x-circle-fill"></i>
  </button>
</div>

Shortcut ​

Sqrl custom

Command or global search: trailing input-group-shortcut inside input-group-merge. Same action as the shortcut; aria-label on the control.

html
<div class="input-group input-group-merge">
  <span class="input-group-text"><i class="bi bi-search"></i></span>
  <input
    class="form-control"
    type="text"
    role="searchbox"
    autocomplete="off"
    placeholder="Search…"
    aria-label="Search"
  />
  <button
    type="button"
    class="input-group-shortcut"
    aria-label="Open search (⌘K)"
  >
    ⌘K
  </button>
</div>

Sizes ​

form-control-sm is 32px / 13px (the floor). Default is 36px / 14px. -lg is 42px / 14px. Same for form-select.

html
<input
  class="form-control form-control-sm"
  type="text"
  placeholder="Small — 32px · 13px"
/>
<input class="form-control" type="text" placeholder="Default — 36px · 14px" />
<input
  class="form-control form-control-lg"
  type="text"
  placeholder="Large — 42px · 14px"
/>

Textarea ​

form-control with rows. Same label pattern as input.

html
<label class="form-label" for="note">Note</label>
<textarea
  class="form-control"
  id="note"
  rows="4"
  placeholder="Imported from CSV"
></textarea>

Select ​

form-select for a single owner or category choice.

html
<label class="form-label" for="owner">Owner</label>
<select class="form-select" id="owner">
  <option>Marieke de Groot</option>
  <option>Anouk Peters</option>
  <option>Lars Hendriks</option>
</select>

Checkbox ​

form-check with type="checkbox". Label-less in table rows (aria-label on the input). Optional .desc inside the label for a sub-line.

html
<input class="form-check-input" type="checkbox" checked aria-label="Checked" />
<input class="form-check-input" type="checkbox" aria-label="Unchecked" />
<div class="form-check">
  <input class="form-check-input" id="email-opt-in" type="checkbox" checked />
  <label class="form-check-label" for="email-opt-in">
    Email opt-in
    <span class="desc">Include in campaign sends.</span>
  </label>
</div>

Radio ​

Same form-check pattern with type="radio" and a shared name.

html
<div class="form-check">
  <input class="form-check-input" id="priority-normal" name="priority" type="radio" checked />
  <label class="form-check-label" for="priority-normal">Normal</label>
</div>
<div class="form-check">
  <input class="form-check-input" id="priority-urgent" name="priority" type="radio" />
  <label class="form-check-label" for="priority-urgent">Urgent</label>
</div>

Pill radio group ​

Sqrl custom

Two to four short labels in a form. Same form-check markup inside sq-pill-radio. Icons are CSS on the label.

html
<div class="sq-pill-radio" role="radiogroup" aria-label="Interested">
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-yes" name="pill-interested" type="radio" checked />
    <label class="form-check-label" for="pill-interested-yes">Yes</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-no" name="pill-interested" type="radio" />
    <label class="form-check-label" for="pill-interested-no">No</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-unsure" name="pill-interested" type="radio" />
    <label class="form-check-label" for="pill-interested-unsure">Not sure</label>
  </div>
</div>

Switch ​

form-check form-switch — same checkbox input, toggle styling.

html
<div class="form-check form-switch">
  <input class="form-check-input" id="notify-updates" type="checkbox" checked />
  <label class="form-check-label" for="notify-updates">Notify me on status changes</label>
</div>

Range ​

Bootstrap form-range. Label row: d-flex justify-content-between align-items-baseline, output.font-monospace.small.text-secondary (for matches the input id).

35%
html
<div class="mb-3">
  <div class="d-flex justify-content-between align-items-baseline gap-3 mb-1">
    <label class="form-label mb-0" for="deal-probability">Deal probability</label>
    <output class="font-monospace small text-secondary mb-0" for="deal-probability">35%</output>
  </div>
  <input
    class="form-range"
    id="deal-probability"
    type="range"
    min="0"
    max="100"
    value="35"
    step="1"
  />
</div>

Validation ​

is-valid / is-invalid with valid-feedback or invalid-feedback.

Looks good.
Assign an owner before activating this step.
html
<label class="form-label" for="company-valid">Company name</label>
<input
  class="form-control is-valid"
  id="company-valid"
  type="text"
  value="Van den Berg Logistics"
/>
<div class="valid-feedback">Looks good.</div>
<label class="form-label" for="owner-required">Owner</label>
<select class="form-select is-invalid" id="owner-required">
  <option value="">Select an owner</option>
</select>
<div class="invalid-feedback">Assign an owner before activating this step.</div>

Disabled ​

45% opacity, not-allowed cursor, no colour change.

html
<label class="form-label" for="company-locked">Company name</label>
<input
  class="form-control"
  id="company-locked"
  type="text"
  value="Van den Berg Logistics"
  disabled
/>

Rules ​

Labels and validation ​

  • Labels are nouns, no colon (“Company name”, “Owner”).
  • Validation: name the missing field and next step — not “Something went wrong”.

Control choice ​

  • Switch: takes effect immediately. Checkbox: saved with the form submit.
  • Short exclusive pair: stacked radios. Two–four options: sq-pill-radio. More: select. Not segmented (presentation) or nav-pills (page content / property filter) — Choose a control.

Input groups ​

Search: input-group-merge (Sqrl custom), role="searchbox", clear with bi-x-circle-fill. Command palette: input-group-shortcut. Chrome icons: Iconography.

Sizes ​

form-control-sm is the floor (32px); default and -lg for larger fields.