Bootstrap 5 has one of the most comprehensive form systems of any CSS framework. Every form element — input, select, checkbox, radio, range, file — gets consistent styling that works across browsers.

Basic Form Structure

The fundamental pattern: wrap each field in mb-3, pair a form-label with a form-control:

<form>
  <div class="mb-3">
    <label for="name" class="form-label">Full Name</label>
    <input type="text" class="form-control" id="name" placeholder="Gagan Singh">
  </div>

  <div class="mb-3">
    <label for="email" class="form-label">Email Address</label>
    <input type="email" class="form-control" id="email" placeholder="you@example.com">
    <div class="form-text">We'll never share your email.</div>
  </div>

  <div class="mb-3">
    <label for="message" class="form-label">Message</label>
    <textarea class="form-control" id="message" rows="4"
      placeholder="Your message..."></textarea>
  </div>

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

form-text under an input produces small muted helper text. The for/id pair links label to input for accessibility.

Input Sizes

<input class="form-control form-control-sm" placeholder="Small input">
<input class="form-control" placeholder="Default input">
<input class="form-control form-control-lg" placeholder="Large input">

Select Dropdown

<div class="mb-3">
  <label class="form-label">Framework</label>
  <select class="form-select">
    <option selected disabled value="">Choose a framework...</option>
    <option>Angular 21</option>
    <option>Bootstrap 5</option>
    <option>React 19</option>
    <option>Next.js 15</option>
  </select>
</div>

<!-- Multiple select -->
<select class="form-select" multiple>
  <option>Angular</option>
  <option>Bootstrap</option>
  <option>React</option>
</select>

Checkboxes and Radio Buttons

<!-- Checkboxes -->
<div class="mb-3">
  <label class="form-label">Frameworks</label>
  <div class="form-check">
    <input class="form-check-input" type="checkbox" id="cb1" checked>
    <label class="form-check-label" for="cb1">Angular 21</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" type="checkbox" id="cb2">
    <label class="form-check-label" for="cb2">Bootstrap 5</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" type="checkbox" id="cb3" disabled>
    <label class="form-check-label text-muted" for="cb3">Vue (disabled)</label>
  </div>
</div>

<!-- Radio buttons -->
<div class="mb-3">
  <label class="form-label">Plan</label>
  <div class="form-check">
    <input class="form-check-input" type="radio" name="plan" id="r1" value="free">
    <label class="form-check-label" for="r1">Free</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" type="radio" name="plan" id="r2" value="pro" checked>
    <label class="form-check-label" for="r2">Pro — $29</label>
  </div>
</div>

<!-- Inline checkboxes -->
<div class="mb-3">
  <div class="form-check form-check-inline">
    <input class="form-check-input" type="checkbox" id="i1">
    <label class="form-check-label" for="i1">Angular</label>
  </div>
  <div class="form-check form-check-inline">
    <input class="form-check-input" type="checkbox" id="i2">
    <label class="form-check-label" for="i2">React</label>
  </div>
</div>

<!-- Toggle switch -->
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" id="darkToggle">
  <label class="form-check-label" for="darkToggle">Dark Mode</label>
</div>

Input Groups

Attach prefixes, suffixes and buttons to inputs:

<!-- Text prefix -->
<div class="input-group mb-3">
  <span class="input-group-text">https://</span>
  <input type="text" class="form-control" placeholder="yoursite.com">
</div>

<!-- Text suffix -->
<div class="input-group mb-3">
  <input type="text" class="form-control" placeholder="Amount">
  <span class="input-group-text">.00</span>
  <span class="input-group-text">USD</span>
</div>

<!-- Button -->
<div class="input-group mb-3">
  <input type="text" class="form-control" placeholder="Search components...">
  <button class="btn text-white" style="background:#fd4766;">Search</button>
</div>

<!-- Button left -->
<div class="input-group mb-3">
  <button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
    Filter
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Angular</a></li>
    <li><a class="dropdown-item" href="#">React</a></li>
  </ul>
  <input type="text" class="form-control" placeholder="Search...">
</div>

Floating Labels

Labels that animate to the top of the input when focused:

<div class="form-floating mb-3">
  <input type="email" class="form-control" id="floatEmail"
    placeholder="name@example.com">
  <label for="floatEmail">Email address</label>
</div>

<div class="form-floating mb-3">
  <input type="password" class="form-control" id="floatPwd"
    placeholder="Password">
  <label for="floatPwd">Password</label>
</div>

<div class="form-floating mb-3">
  <select class="form-select" id="floatSelect">
    <option selected disabled>Choose...</option>
    <option>Angular</option>
    <option>React</option>
  </select>
  <label for="floatSelect">Framework</label>
</div>

The placeholder attribute is required for floating labels to animate — it can be an empty string.

Form Validation

<form class="needs-validation" novalidate id="validationForm">
  <div class="mb-3">
    <label class="form-label">Email</label>
    <input type="email" class="form-control" required
      placeholder="you@example.com">
    <div class="valid-feedback">Looks good!</div>
    <div class="invalid-feedback">Please provide a valid email.</div>
  </div>

  <div class="mb-3">
    <label class="form-label">Template</label>
    <select class="form-select" required>
      <option value="">Choose a template...</option>
      <option>Marvel Dashboard — $29</option>
      <option>PORTO Bootstrap — $19</option>
    </select>
    <div class="invalid-feedback">Please select a template.</div>
  </div>

  <div class="form-check mb-3">
    <input class="form-check-input" type="checkbox" id="terms" required>
    <label class="form-check-label" for="terms">
      I agree to the <a href="#" style="color:#fd4766;">terms</a>
    </label>
    <div class="invalid-feedback">You must agree before submitting.</div>
  </div>

  <button type="submit" class="btn text-white" style="background:#fd4766;">Submit</button>
</form>

<script>
  document.getElementById('validationForm').addEventListener('submit', function(e) {
    if (!this.checkValidity()) {
      e.preventDefault()
      e.stopPropagation()
    }
    this.classList.add('was-validated')
  })
</script>

Horizontal Form Layout

<form>
  <div class="row mb-3">
    <label class="col-sm-3 col-form-label">Email</label>
    <div class="col-sm-9">
      <input type="email" class="form-control" placeholder="you@example.com">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-sm-3 col-form-label">Password</label>
    <div class="col-sm-9">
      <input type="password" class="form-control" placeholder="••••••••">
    </div>
  </div>
  <div class="row">
    <div class="col-sm-9 offset-sm-3">
      <button type="submit" class="btn text-white" style="background:#fd4766;">Sign In</button>
    </div>
  </div>
</form>

Inline Form

<form class="d-flex gap-2 align-items-center flex-wrap">
  <label class="visually-hidden" for="inlineEmail">Email</label>
  <input type="email" class="form-control" id="inlineEmail"
    placeholder="Email" style="max-width:220px;">
  <label class="visually-hidden" for="inlinePwd">Password</label>
  <input type="password" class="form-control" id="inlinePwd"
    placeholder="Password" style="max-width:160px;">
  <div class="form-check mb-0">
    <input class="form-check-input" type="checkbox" id="inlineRemember">
    <label class="form-check-label" for="inlineRemember">Remember me</label>
  </div>
  <button type="submit" class="btn text-white" style="background:#fd4766;">Sign In</button>
</form>

visually-hidden hides labels from view but keeps them accessible for screen readers — important for inline forms where labels are implied by placeholders.

Disabled and Readonly

<input class="form-control" value="Disabled input" disabled>
<input class="form-control" value="Read-only value" readonly>
<input class="form-control bg-light" value="Read-only plain" readonly>

readonly inputs keep their value in form submissions. disabled inputs are excluded from form data.

Frequently Asked Questions

Wrap each form control in a div with class mb-3. Add label with form-label and input with form-control. Basic pattern: <div class='mb-3'><label class='form-label'>Email</label><input type='email' class='form-control' placeholder='you@example.com'></div>.
Add novalidate to the form element. Add required (and other attributes) to inputs. On submit, call form.checkValidity(). If false, add was-validated class to the form — Bootstrap's CSS then shows green (valid-feedback) or red (invalid-feedback) states on each field.
form-control styles text inputs, textareas, file inputs and password fields. form-select styles select dropdown elements with a custom arrow. Both apply Bootstrap's consistent border, padding, focus ring and disabled states.
form-control and form-select are already full width (width:100%) by default. They fill whatever container they're in. To limit width, constrain the parent: <div style='max-width:400px'> or use Bootstrap's column classes: <div class='col-md-6'>.

Need a Full Bootstrap 5 Admin Dashboard?

Get a complete Angular 21 + Bootstrap 5 dashboard with 50+ components — built by the same team behind BootstrapPlanet.

Browse Templates →

Use code FIRST30 for 30% off your first purchase.

Related Components