A form is more than a stack of inputs. Bootstrap offers floating labels for compact, modern-looking fields, and a set of conventions built on the grid for horizontal, inline and multi-column layouts. After this lesson you will be able to lay out a two-column signup form, a horizontal settings form with right-aligned labels, and a single-line search bar, each responsive by default.
A floating label sits inside the input like a placeholder and slides up when the field has focus or a value. The markup order matters: the <input> comes before the <label>, and a placeholder attribute is required even though it is not displayed:
<div class="form-floating mb-3">
<input type="text" class="form-control" id="company" placeholder="Company">
<label for="company">Company</label>
</div>The CSS uses :placeholder-shown to know whether the field is empty, which is why the placeholder cannot be omitted.
Floating labels also work with .form-select and textareas:
<div class="form-floating mb-3">
<select class="form-select" id="tz" aria-label="Time zone">
<option selected>Asia/Kolkata</option>
<option>Europe/London</option>
</select>
<label for="tz">Time zone</label>
</div>
<div class="form-floating">
<textarea class="form-control" id="notes" placeholder="Notes" style="height: 100px"></textarea>
<label for="notes">Notes</label>
</div>Set an explicit height on textareas, otherwise they collapse to a single line. Floating labels do not support form-control-sm or -lg, and they can sit inside an .input-group only when the group has no validation feedback text.
Use the regular grid with g-* gutters. g-3 is the conventional spacing for form rows:
<form class="row g-3">
<div class="col-md-6">
<label for="first" class="form-label">First name</label>
<input class="form-control" id="first">
</div>
<div class="col-md-6">
<label for="last" class="form-label">Last name</label>
<input class="form-control" id="last">
</div>
<div class="col-md-8">
<label for="street" class="form-label">Street</label>
<input class="form-control" id="street">
</div>
<div class="col-md-4">
<label for="zip" class="form-label">ZIP</label>
<input class="form-control" id="zip">
</div>
</form>Because the gutter is vertical as well as horizontal, you do not need mb-3 on every field. For very compact forms use g-2.
A horizontal form places the label and control side by side. Each field is a .row, the label gets .col-form-label (which adds padding to align its text with the input text) and a column width:
<form>
<div class="row mb-3">
<label for="hEmail" class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" id="hEmail">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3">Notifications</div>
<div class="col-sm-9">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hNotify">
<label class="form-check-label" for="hNotify">Send weekly digest</label>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-9 offset-sm-3">
<button class="btn btn-primary">Save</button>
</div>
</div>
</form>Below sm the labels stack above the inputs automatically. Match col-form-label-sm / -lg with form-control-sm / -lg when sizing.
Bootstrap 5 removed the .form-inline class. Build inline forms with the grid or flex utilities plus align-items-center and .visually-hidden labels:
<form class="row row-cols-lg-auto g-3 align-items-center">
<div class="col-12">
<label class="visually-hidden" for="q">Search</label>
<input class="form-control" id="q" placeholder="Search">
</div>
<div class="col-12">
<label class="visually-hidden" for="cat">Category</label>
<select class="form-select" id="cat">
<option selected>All</option>
<option>Docs</option>
</select>
</div>
<div class="col-12">
<button class="btn btn-primary">Go</button>
</div>
</form>row-cols-lg-auto makes each column content-sized from lg up; below that the fields stack full width.
col-auto fits a column to its content, which is handy for a short field like a quantity next to a full-width one:
<div class="row g-2">
<div class="col-auto"><input class="form-control" style="width: 6rem" value="1"></div>
<div class="col"><input class="form-control" placeholder="Item name"></div>
</div><fieldset> and <legend>; Bootstrap resets their default styling.type="submit" so Enter submits.<form> with .vstack.gap-3 is a clean alternative to mb-3 on every field for single-column forms.Why does a floating-label input need a `placeholder` attribute?
.form-floating wraps an input followed by its label; the input must have a placeholder.row g-3 with col-* per field; the gutter supplies vertical spacing..row per field with col-form-label on the label column.row-cols-lg-auto and align-items-center, with labels kept accessible via .visually-hidden.col-auto fits a column to its content for short fields.Next lesson: Form Validation - show valid and invalid states with HTML5 constraints, custom feedback messages and server-side classes.