Form Layout

Knowing the control classes from the last lesson only gets you individual fields — a real form also needs spacing between them and, often, a grid to line labels up with inputs. Bootstrap 5 gives you three layout patterns: plain stacked spacing, a horizontal grid layout, and inline flex layouts. This lesson builds all three, finishing with the complete TrailMap "Submit a Trail" form laid out horizontally.

Stacked Layout: .mb-3 Replaces .form-group

In Bootstrap 3 and 4, every field was wrapped in a <div class="form-group"> to get consistent spacing below it. Bootstrap 5 removed .form-group entirely. The replacement isn't a new class with a similar name — it's just the plain spacing utility .mb-3 (margin-bottom, step 3) applied directly to the wrapper. One less special-purpose class to remember, and it composes with every other spacing utility you already know.

<!-- Bootstrap 4 (old) -->
<div class="form-group">
  <label>Region</label>
  <input type="text" class="form-control">
</div>

<!-- Bootstrap 5 (current) -->
<div class="mb-3">
  <label class="form-label">Region</label>
  <input type="text" class="form-control">
</div>
BS4 → BS5 change: There is no .form-group in Bootstrap 5 — searching your CSS or a component library for it and finding nothing is expected, not a bug. Swap it for .mb-3 (or whatever spacing value fits your layout) and add the new .form-label class to labels.

Horizontal Layout: Grid Rows, Columns, and .col-form-label

For label-beside-input rows, reuse the grid: a .row containing a label column and an input column. Add .col-form-label to the label so its vertical padding lines up with the input's height instead of sitting flush against the top.

<div class="row mb-3">
  <label for="trailRegion" class="col-sm-2 col-form-label">Region</label>
  <div class="col-sm-10">
    <input type="text" class="form-control" id="trailRegion" placeholder="e.g. Blue Ridge Mountains">
  </div>
</div>

Inline Forms: Flex and Gap Utilities

Bootstrap 5 dropped the dedicated .form-inline class from Bootstrap 4. To lay controls out on one line now, reach for the same flexbox utilities you'd use anywhere else: .d-flex on the container, .gap-2 for consistent spacing between items, and .align-items-center to keep labels and inputs vertically centered.

<!-- A compact inline trail search + region filter -->
<form class="d-flex align-items-center gap-2">
  <label class="visually-hidden" for="quickSearch">Search trails</label>
  <input type="search" class="form-control" id="quickSearch" placeholder="Search trails...">
  <button type="submit" class="btn btn-primary">Search</button>
</form>

Worked Example: The Full TrailMap "Submit a Trail" Form

Putting stacked spacing and the horizontal grid together — TrailMap's real submission form, with every field type from the previous lesson laid out label-left, input-right:

<form>
  <div class="row mb-3">
    <label for="trailName" class="col-sm-3 col-form-label">Trail Name</label>
    <div class="col-sm-9">
      <input type="text" class="form-control" id="trailName">
    </div>
  </div>

  <div class="row mb-3">
    <label for="trailDescription" class="col-sm-3 col-form-label">Description</label>
    <div class="col-sm-9">
      <textarea class="form-control" id="trailDescription" rows="3"></textarea>
    </div>
  </div>

  <div class="row mb-3">
    <label for="trailDifficulty" class="col-sm-3 col-form-label">Difficulty</label>
    <div class="col-sm-9">
      <select class="form-select" id="trailDifficulty">
        <option value="easy">Easy</option>
        <option value="moderate">Moderate</option>
        <option value="hard">Hard</option>
      </select>
    </div>
  </div>

  <div class="row mb-3">
    <label for="trailDistance" class="col-sm-3 col-form-label">Distance (mi)</label>
    <div class="col-sm-9">
      <input type="number" class="form-control" id="trailDistance" step="0.1" min="0">
    </div>
  </div>

  <div class="row mb-3">
    <label for="trailRegion" class="col-sm-3 col-form-label">Region</label>
    <div class="col-sm-9">
      <input type="text" class="form-control" id="trailRegion">
    </div>
  </div>

  <div class="row mb-3">
    <label for="trailPhoto" class="col-sm-3 col-form-label">Photo</label>
    <div class="col-sm-9">
      <input type="file" class="form-control" id="trailPhoto" accept="image/*">
    </div>
  </div>

  <div class="row mb-3">
    <div class="col-sm-9 offset-sm-3">
      <div class="form-check">
        <input class="form-check-input" type="checkbox" id="agreeTerms">
        <label class="form-check-label" for="agreeTerms">I confirm this trail information is accurate</label>
      </div>
    </div>
  </div>

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

Every row follows the same shape: a .col-form-label for the label, a matching-width column for the control, wrapped in .row.mb-3 for spacing between rows.

Next up: A layout only looks right until a user leaves a required field empty. See how Bootstrap flags that in Form Validation next.