Input groups
A field joined to what belongs to it - a unit, a prefix, a button, a choice - into one control. The borders meet by themselves; a menu or a hidden element inside the group is left out of the joining.
Examples
input-group around a form-control or a form-select and its parts: input-group-text for words and icons, a btn for an action. An icon inside the field itself is form-adorn.
<div class="input-group">
<input class="form-control" type="text" inputmode="decimal" value="2,500" aria-label="Adult price" aria-describedby="input-group-basic-unit">
<span class="input-group-text" id="input-group-basic-unit">THB</span>
</div>
<div class="input-group">
<span class="input-group-text">https://</span>
<input class="form-control" type="text" value="northbay.example" aria-label="Site address">
</div>
<div class="input-group">
<input class="form-control" type="text" value="R7K2-9QXM" readonly aria-label="Access code">
<button class="btn" type="button"><i class="bi bi-clipboard" aria-hidden="true"></i>Copy</button>
</div>A plain btn wears the field's line and an accent face, so the group reads as one control; a plain btn-icon reads as input-group-text. A solid, outline, subtle or text button keeps its own look.
With a choice
A form-select or a check joins the same way; a check goes inside an input-group-text.
<div class="input-group">
<select class="form-select" aria-label="Currency">
<option>THB</option>
<option>USD</option>
<option>EUR</option>
</select>
<input class="form-control" type="text" inputmode="decimal" value="1,900" aria-label="Child price">
</div>
<div class="input-group">
<label class="input-group-text"><input class="check" type="checkbox" checked>Discount</label>
<input class="form-control" type="text" inputmode="decimal" value="10" aria-label="Discount, percent">
<span class="input-group-text">%</span>
</div>With a floating label
A form-floating grows in the group as a field does, and its parts take its height: an icon or a unit in input-group-text, a btn or a square btn-icon. A password keeps its --reveal button and its strength; the error goes under the group, in a form-field.
<div class="input-group">
<span class="input-group-text"><i class="bi bi-envelope" aria-hidden="true"></i></span>
<div class="form-floating">
<input class="form-control" id="input-group-floating-mail" type="email" placeholder="name@example.com" autocomplete="email">
<label for="input-group-floating-mail">E-mail</label>
</div>
</div>
<div class="form-field">
<div class="input-group">
<div class="form-floating">
<input class="form-control" id="input-group-floating-password" type="password" placeholder="Password" autocomplete="new-password" aria-describedby="input-group-floating-level">
<label for="input-group-floating-password">New password</label>
</div>
<button class="btn btn-icon" type="button" commandfor="input-group-floating-password" command="--reveal" aria-pressed="false" aria-label="Show the password"><i class="bi bi-eye" aria-hidden="true"></i></button>
</div>
<meter class="meter" min="0" max="4" low="2" high="3" optimum="4" value="0" data-strength="input-group-floating-password" aria-label="Password strength"></meter>
<div class="form-text" id="input-group-floating-level" data-strength="input-group-floating-password"></div>
</div>
<div class="input-group">
<div class="form-floating">
<input class="form-control" id="input-group-floating-share" type="text" inputmode="numeric" value="20" aria-describedby="input-group-floating-unit">
<label for="input-group-floating-share">Partner share</label>
</div>
<span class="input-group-text" id="input-group-floating-unit">%</span>
</div>
<div class="input-group">
<div class="form-floating">
<input class="form-control font-monospace" id="input-group-floating-secret" type="text" value="JBSWY3DPEHPK3PXP" readonly>
<label for="input-group-floating-secret">Secret key</label>
</div>
<button class="btn" type="button"><i class="bi bi-clipboard" aria-hidden="true"></i>Copy</button>
</div>With a menu
The menu sits in the group beside its button; the group joins only what it shows.
<div class="input-group">
<input class="form-control" type="search" placeholder="Search excursions" aria-label="Search excursions">
<button class="btn" type="button" commandfor="input-group-menu-in" command="toggle-popover" aria-haspopup="menu">Everywhere<i class="bi bi-chevron-down" aria-hidden="true"></i></button>
<div id="input-group-menu-in" class="menu" popover role="menu" aria-label="Search in">
<button class="menu-item" type="button" role="menuitemradio" aria-checked="true">Everywhere</button>
<button class="menu-item" type="button" role="menuitemradio" aria-checked="false">Titles</button>
<button class="menu-item" type="button" role="menuitemradio" aria-checked="false">Descriptions</button>
</div>
</div>Small, in a field
input-group-sm sizes every part of the group; form-field carries the label, the hint and the error outside it.
<div class="form-field">
<label class="form-label" for="input-group-field-months">Free months</label>
<div class="input-group input-group-sm">
<input class="form-control" id="input-group-field-months" type="text" inputmode="numeric" value="3" aria-describedby="input-group-field-hint">
<span class="input-group-text">months</span>
<button class="btn btn-sm btn-icon" type="button" aria-label="Remove"><i class="bi bi-trash" aria-hidden="true"></i></button>
</div>
<div class="form-text" id="input-group-field-hint">Given with a yearly plan.</div>
</div>States
| class | rest | :hover | :focus | aria-invalid | disabled |
|---|---|---|---|---|---|
| input-group | THB |
THB |
THB |
THB |
THB |
Keyboard and accessibility
- Every field of a group has its own name - a
<label>oraria-label. The words beside it are not its name: point at a unit witharia-describedby, so it reads as “Adult price, 2,500, THB”. - The parts keep their own keys: Tab goes from the field to its button, a menu opens as every menu does.
- An error goes under the group, in its
form-field, never inside it.
Tokens
From css/components/input-group.css. It declares --redz-btn-bg, --redz-btn-fg, --redz-btn-hover, --redz-btn-hover-fg, --redz-group-bg, --redz-group-fg, --redz-group-hover, --redz-group-hover-fg on its root, never on rows or items.
It reads the theme's --redz-control-height-float, --redz-primary-subtle, --redz-primary, --redz-text, --redz-border-strong, --redz-bg-page, --redz-text-muted, --redz-bg-hover, --redz-space-8, --redz-space-12, --redz-radius-8, --redz-control-height-sm, --redz-radius-6, --redz-fs-12.