Bootstrap Search Box: 16 Examples With Autocomplete

Most Bootstrap search boxes come down to an input with type="search", a submit button, and the form-control, input-group and btn classes. None of that markup searches anything, though. Even Bootstrap's own documentation search runs on Algolia's DocSearch, according to the Bootstrap README.

Below are 16 Bootstrap search box examples you can copy, followed by a guide to markup, placement, sizing, accessibility and making the box actually search.

By Bogdan Sandu · Updated October 29, 2026

Every example runs on Bootstrap 5.3.8 from the jsDelivr CDN. Add these tags to your page, then paste an example's HTML, CSS and JS.

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.2/font/bootstrap-icons.min.css" rel="stylesheet" integrity="sha384-nWN3KqaaVcbEsCjLSV+2jMjh62Iny/+mN3srM8TZeM8N6aj7eDl5wwYggjAJ4/sJ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>

Search in navbars, headers and docs

Where the box lives decides most of its markup. These four put it inside a collapsing navbar, an icon that grows on focus, a full-screen offcanvas panel for phones and a docs sidebar with a slash shortcut.

Docs sidebar filter with a slash shortcut

  • <search>
  • kbd
  • nav flex-column
  • aria-keyshortcuts

Press / and type a page name.

A documentation sidebar wrapped in the native search element, with a kbd hint that tells keyboard users to press slash. The script focuses the field on slash unless you are already typing somewhere, filters the page links with d-none, hides empty sections and reports the count in a status line.

View code
<aside class="bsr-docs w-100 bg-body border rounded-3 p-3" aria-label="Documentation">
  <p class="fw-bold mb-3 bsr-docs-head">Ripple UI docs</p>
  <search class="d-block position-relative mb-2">
    <label for="bsr-docs-q" class="visually-hidden">Filter documentation pages</label>
    <input id="bsr-docs-q" type="search" class="form-control bsr-docs-input" placeholder="Filter pages" autocomplete="off" aria-keyshortcuts="/" aria-describedby="bsr-docs-tip">
    <kbd class="bsr-docs-kbd" aria-hidden="true">/</kbd>
    <span id="bsr-docs-tip" class="visually-hidden">Press slash to jump to this field.</span>
  </search>
  <p class="small text-body-secondary mb-2 bsr-docs-count" role="status">14 pages</p>
  <nav aria-label="Docs pages">
    <div class="bsr-docs-sec mb-2">
      <h2 class="small fw-semibold text-uppercase text-body-secondary mb-1 bsr-docs-label">Getting started</h2>
      <ul class="nav flex-column">
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Introduction</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Download</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Color modes</a></li>
      </ul>
    </div>
    <div class="bsr-docs-sec mb-2">
      <h2 class="small fw-semibold text-uppercase text-body-secondary mb-1 bsr-docs-label">Layout</h2>
      <ul class="nav flex-column">
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Breakpoints</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Containers</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Grid</a></li>
      </ul>
    </div>
    <div class="bsr-docs-sec mb-2">
      <h2 class="small fw-semibold text-uppercase text-body-secondary mb-1 bsr-docs-label">Components</h2>
      <ul class="nav flex-column">
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Accordion</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Dropdowns</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Modal</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Navbar</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Offcanvas</a></li>
      </ul>
    </div>
    <div class="bsr-docs-sec">
      <h2 class="small fw-semibold text-uppercase text-body-secondary mb-1 bsr-docs-label">Forms</h2>
      <ul class="nav flex-column">
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Form controls</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Input group</a></li>
        <li class="bsr-docs-item"><a class="nav-link py-1 px-2" href="#">Validation</a></li>
      </ul>
    </div>
  </nav>
  <p class="small text-body-secondary mb-0 d-none bsr-docs-empty">No pages match. Try another word.</p>
</aside>

Hero, travel and filter search forms

Bigger boxes that carry a page: a hero with a category select, a stay search with date inputs, a help center with Bootstrap validation and a recipe search with filter chips.

Hero search with a category select

  • input-group-lg
  • form-select
  • requestSubmit()
  • aria-label

Fill the fields and submit.

A job board hero puts a form-select and the query field in one input-group-lg, so both grow together. The select has its own aria-label, the icon button keeps an accessible name when its text hides on phones, and the popular-search buttons fill the field and call requestSubmit() so the same submit handler runs.

View code
<section class="bsr-hero px-3 px-sm-5 py-5 text-center">
  <h2 class="display-6 fw-bold mb-2">Find design work that fits</h2>
  <p class="mb-4 bsr-hero-lead">2,480 open roles from studios, agencies and product teams.</p>
  <form class="bsr-hero-form mx-auto" role="search" aria-label="Job search">
    <div class="input-group input-group-lg">
      <select class="form-select bsr-hero-cat" id="bsr-hero-cat" aria-label="Category">
        <option value="All">All roles</option>
        <option value="Design">Design</option>
        <option value="Engineering">Engineering</option>
        <option value="Writing">Writing</option>
        <option value="Marketing">Marketing</option>
      </select>
      <input type="search" class="form-control" id="bsr-hero-q" name="q" placeholder="Job title or skill" aria-label="Job title or skill">
      <button class="btn bsr-hero-btn" type="submit" aria-label="Search jobs"><i class="bi bi-search" aria-hidden="true"></i><span class="d-none d-sm-inline ms-2">Search</span></button>
    </div>
  </form>
  <div class="d-flex flex-wrap justify-content-center align-items-center gap-2 mt-3 small">
    <span class="bsr-hero-lead">Popular:</span>
    <button type="button" class="btn btn-sm rounded-pill bsr-hero-tag">UX writer</button>
    <button type="button" class="btn btn-sm rounded-pill bsr-hero-tag">Motion designer</button>
    <button type="button" class="btn btn-sm rounded-pill bsr-hero-tag">Design systems</button>
  </div>
  <p class="mt-3 mb-0 bsr-hero-out" role="status"></p>
</section>

Stay search with dates and guests

  • <search>
  • type="date"
  • was-validated
  • setCustomValidity()

Fill the fields and submit.

A travel card wraps the form in the native search element and uses the grid to lay out a destination field, two native date inputs and a guests select. Bootstrap has no datepicker, so the script sets min dates and uses setCustomValidity() to reject a check-out before check-in, then the novalidate plus was-validated pattern shows the feedback.

View code
<search class="bsr-trip d-block w-100 bg-body rounded-4 shadow-sm overflow-hidden" aria-label="Stay search">
  <img src="coast-road.webp" alt="Wooded cliffs and a winding coast road above a calm sea in evening light" class="bsr-trip-img d-block w-100" width="800" height="600">
  <form class="p-3 p-sm-4 bsr-trip-form" novalidate>
    <h2 class="h5 fw-bold mb-3">Find a stay on the coast</h2>
    <div class="row g-3">
      <div class="col-12 col-md-4">
        <label for="bsr-trip-where" class="form-label">Where</label>
        <input type="search" class="form-control" id="bsr-trip-where" list="bsr-trip-places" placeholder="Town or region" autocomplete="off" required>
        <datalist id="bsr-trip-places">
          <option value="Cliffside village"></option>
          <option value="Harbor town"></option>
          <option value="Olive valley"></option>
        </datalist>
        <div class="invalid-feedback">Enter a destination.</div>
      </div>
      <div class="col-12 col-sm-6 col-md-3">
        <label for="bsr-trip-in" class="form-label">Check-in</label>
        <input type="date" class="form-control" id="bsr-trip-in" required>
        <div class="invalid-feedback">Pick a check-in date.</div>
      </div>
      <div class="col-12 col-sm-6 col-md-3">
        <label for="bsr-trip-out" class="form-label">Check-out</label>
        <input type="date" class="form-control" id="bsr-trip-out" required>
        <div class="invalid-feedback">Pick a date after check-in.</div>
      </div>
      <div class="col-12 col-md-2">
        <label for="bsr-trip-guests" class="form-label">Guests</label>
        <select class="form-select" id="bsr-trip-guests">
          <option value="1">1</option>
          <option value="2" selected>2</option>
          <option value="3">3</option>
          <option value="4">4</option>
        </select>
      </div>
      <div class="col-12 d-flex flex-column flex-sm-row align-items-sm-center justify-content-between gap-3">
        <p class="mb-0 fw-semibold bsr-trip-result" role="status"></p>
        <button type="submit" class="btn btn-primary px-4 bsr-trip-go"><i class="bi bi-search me-2" aria-hidden="true"></i>Search stays</button>
      </div>
    </div>
  </form>
</search>

Help center search with validation

  • has-validation
  • minlength
  • invalid-feedback
  • input-group-lg

Fill the fields and submit.

A support page search that refuses one- and two-letter queries. The input group carries .has-validation so the rounded corners stay right when the invalid-feedback shows, and the form uses novalidate with checkValidity() and was-validated. Topic buttons fill the field and submit it.

View code
<search class="bsr-help d-block w-100 text-center">
  <h2 class="h3 fw-bold mb-2">How can we help?</h2>
  <p class="text-body-secondary mb-4">Search 340 articles about orders, billing and returns.</p>
  <form class="bsr-help-form text-start" novalidate>
    <label for="bsr-help-q" class="visually-hidden">Search help articles</label>
    <div class="input-group input-group-lg has-validation">
      <span class="input-group-text bg-body"><i class="bi bi-search" aria-hidden="true"></i></span>
      <input type="search" class="form-control" id="bsr-help-q" placeholder="Search help" required minlength="3" aria-describedby="bsr-help-fb">
      <button class="btn bsr-help-btn" type="submit">Search</button>
      <div class="invalid-feedback" id="bsr-help-fb">Type at least 3 characters.</div>
    </div>
  </form>
  <div class="d-flex flex-wrap justify-content-center gap-2 mt-3" role="group" aria-label="Popular topics">
    <button type="button" class="btn btn-sm btn-light border rounded-pill bsr-help-topic">Track my order</button>
    <button type="button" class="btn btn-sm btn-light border rounded-pill bsr-help-topic">Change payment method</button>
    <button type="button" class="btn btn-sm btn-light border rounded-pill bsr-help-topic">Start a return</button>
  </div>
  <p class="mt-3 mb-0 fw-semibold bsr-help-out" role="status"></p>
</search>

Recipe search with filter chips

  • btn-check
  • badge
  • list-group
  • role="status"

Fill the fields and submit.

Filter chips are real checkboxes styled with .btn-check and pill buttons, so they work with Space and announce their checked state. The script matches the query and every checked chip against data attributes, toggles d-none on the list items and keeps a polite count up to date.

View code
<div class="bsr-chips w-100 bg-body border rounded-4 p-3 p-sm-4">
  <search>
    <label for="bsr-chips-q" class="form-label fw-bold">Search recipes</label>
    <div class="input-group mb-3">
      <span class="input-group-text"><i class="bi bi-search" aria-hidden="true"></i></span>
      <input id="bsr-chips-q" type="search" class="form-control" placeholder="Orzo, curry, soup" autocomplete="off">
    </div>
    <div class="d-flex flex-wrap gap-2 mb-3" role="group" aria-label="Filters">
      <input type="checkbox" class="btn-check bsr-chip" id="bsr-chip-veg" value="veg" autocomplete="off">
      <label class="btn btn-sm rounded-pill bsr-chip-btn" for="bsr-chip-veg">Vegetarian</label>
      <input type="checkbox" class="btn-check bsr-chip" id="bsr-chip-quick" value="quick" autocomplete="off">
      <label class="btn btn-sm rounded-pill bsr-chip-btn" for="bsr-chip-quick">Under 30 min</label>
      <input type="checkbox" class="btn-check bsr-chip" id="bsr-chip-gf" value="gf" autocomplete="off">
      <label class="btn btn-sm rounded-pill bsr-chip-btn" for="bsr-chip-gf">Gluten-free</label>
      <input type="checkbox" class="btn-check bsr-chip" id="bsr-chip-pot" value="pot" autocomplete="off">
      <label class="btn btn-sm rounded-pill bsr-chip-btn" for="bsr-chip-pot">One pot</label>
    </div>
  </search>
  <p class="small text-body-secondary mb-2 bsr-chips-count" role="status">6 recipes</p>
  <ul class="list-group bsr-chips-list">
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="veg quick pot"><span><span class="d-block fw-semibold">Lemon orzo with peas</span><span class="small text-body-secondary">25 min</span></span><span class="badge rounded-pill bsr-chips-badge">Vegetarian</span></li>
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="veg gf pot"><span><span class="d-block fw-semibold">Chickpea and spinach curry</span><span class="small text-body-secondary">35 min</span></span><span class="badge rounded-pill bsr-chips-badge">Gluten-free</span></li>
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="gf quick"><span><span class="d-block fw-semibold">Sheet-pan salmon and greens</span><span class="small text-body-secondary">25 min</span></span><span class="badge rounded-pill bsr-chips-badge">Gluten-free</span></li>
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="veg gf"><span><span class="d-block fw-semibold">Mushroom risotto</span><span class="small text-body-secondary">45 min</span></span><span class="badge rounded-pill bsr-chips-badge">Vegetarian</span></li>
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="gf pot"><span><span class="d-block fw-semibold">Chicken tortilla soup</span><span class="small text-body-secondary">40 min</span></span><span class="badge rounded-pill bsr-chips-badge">One pot</span></li>
    <li class="list-group-item d-flex justify-content-between align-items-center gap-2 bsr-chips-item" data-bsr-tags="veg quick"><span><span class="d-block fw-semibold">Sesame soba noodle salad</span><span class="small text-body-secondary">20 min</span></span><span class="badge rounded-pill bsr-chips-badge">Under 30 min</span></li>
  </ul>
  <p class="mb-0 mt-2 d-none bsr-chips-empty">No recipes match. <button type="button" class="btn btn-link p-0 align-baseline bsr-chips-reset">Clear search and filters</button></p>
</div>

Live suggestions, palettes and filtering

Search that reacts while you type. A small amount of vanilla JavaScript filters local data, and Bootstrap list groups, modals and tables display the results, with the ARIA combobox pattern where arrow keys move through suggestions.

Autocomplete with keyboard suggestions

  • role="combobox"
  • aria-activedescendant
  • list-group-item-action
  • mark

Type ba or lis, then use the arrow keys and Enter.

The ARIA combobox pattern on a Bootstrap list group: the input keeps focus, aria-expanded says whether the list is open and aria-activedescendant points at the option you reach with the arrow keys. Suggestions come from a local array and are built with createElement and textContent, and the matching letters are wrapped in a mark element.

View code
<div class="bsr-ac w-100">
  <form class="bsr-ac-form" role="search" aria-label="Flight search">
    <label for="bsr-ac-q" class="form-label fw-bold">Flying to</label>
    <div class="position-relative">
      <i class="bi bi-airplane bsr-ac-icon" aria-hidden="true"></i>
      <input id="bsr-ac-q" type="search" class="form-control form-control-lg bsr-ac-input" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="bsr-ac-list" autocomplete="off" placeholder="City or airport code">
      <ul id="bsr-ac-list" class="list-group shadow bsr-ac-list d-none" role="listbox" aria-label="Airports"></ul>
    </div>
  </form>
  <p class="small text-body-secondary mt-2 mb-0 bsr-ac-out" role="status">Try ba, lis or a code like CPH.</p>
</div>

Command palette opened with Ctrl+K

  • modal
  • data-bs-theme="dark"
  • shown.bs.modal
  • kbd

Click the button or press Ctrl+K.

A search button with a kbd hint opens a dark modal, and Ctrl+K or Cmd+K toggles it through the Modal API. The script focuses the input on shown.bs.modal, filters a command list as you type, keeps the first match active, and lets the arrow keys and Enter run a command, using the same combobox attributes as the autocomplete demo.

View code
<div class="bsr-cmd-wrap w-100">
  <div class="d-flex align-items-center justify-content-between gap-3 bg-body border rounded-3 px-3 py-2 shadow-sm">
    <span class="fw-bold">Ledgerly</span>
    <button type="button" class="btn bsr-cmd-open d-flex align-items-center gap-2" data-bs-toggle="modal" data-bs-target="#bsr-cmd" aria-keyshortcuts="Control+K Meta+K">
      <i class="bi bi-search" aria-hidden="true"></i><span>Search or jump to</span><kbd class="d-none d-sm-inline bsr-cmd-kbd">Ctrl K</kbd>
    </button>
  </div>
  <p class="small text-body-secondary mt-3 mb-0 text-center bsr-cmd-out" role="status">Press Ctrl+K or click the search button.</p>
</div>
<div class="modal fade bsr-cmd" id="bsr-cmd" tabindex="-1" aria-labelledby="bsr-cmd-title" aria-hidden="true" data-bs-theme="dark">
  <div class="modal-dialog">
    <div class="modal-content">
      <h2 class="visually-hidden" id="bsr-cmd-title">Command palette</h2>
      <div class="d-flex align-items-center gap-2 px-3 border-bottom bsr-cmd-field">
        <i class="bi bi-search text-body-secondary" aria-hidden="true"></i>
        <input type="search" id="bsr-cmd-q" class="form-control border-0 bg-transparent py-3 bsr-cmd-input" role="combobox" aria-expanded="true" aria-controls="bsr-cmd-list" aria-autocomplete="list" aria-label="Search commands" placeholder="Type a command or page" autocomplete="off">
        <kbd class="bsr-cmd-kbd">Esc</kbd>
      </div>
      <ul class="list-unstyled mb-0 p-2 bsr-cmd-list" id="bsr-cmd-list" role="listbox" aria-label="Commands"></ul>
      <p class="px-3 py-4 mb-0 text-body-secondary d-none bsr-cmd-empty">No commands match.</p>
    </div>
  </div>
</div>

Live table filter with a no-results row

  • table-hover
  • d-none
  • colspan
  • role="status"

Start typing and use the arrow keys.

The input filters the table rows on every input event by toggling d-none, then shows a no-results row that repeats the query when nothing is left. A role="status" line, which is polite by default, reads the new count, so screen reader users hear the result without losing their place in the field.

View code
<div class="bsr-tbl w-100 bg-body border rounded-3 shadow-sm">
  <div class="d-flex flex-column flex-sm-row gap-2 align-items-sm-center justify-content-between p-3 border-bottom">
    <h2 class="h6 fw-bold mb-0">Recent orders</h2>
    <search class="bsr-tbl-search">
      <label for="bsr-tbl-q" class="visually-hidden">Filter orders</label>
      <div class="position-relative">
        <i class="bi bi-funnel bsr-tbl-icon" aria-hidden="true"></i>
        <input id="bsr-tbl-q" type="search" class="form-control bsr-tbl-input" placeholder="Customer or status" autocomplete="off">
      </div>
    </search>
  </div>
  <div class="table-responsive">
    <table class="table table-hover align-middle mb-0">
      <thead>
        <tr><th scope="col" class="d-none d-sm-table-cell">Order</th><th scope="col">Customer</th><th scope="col">Status</th><th scope="col" class="text-end">Total</th></tr>
      </thead>
      <tbody>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3108</td><td>Ana Ruiz</td><td><span class="badge text-bg-success">Paid</span></td><td class="text-end">$184.00</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3107</td><td>Owen Kerr</td><td><span class="badge text-bg-warning">Pending</span></td><td class="text-end">$62.50</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3106</td><td>Lena Hart</td><td><span class="badge text-bg-success">Paid</span></td><td class="text-end">$310.00</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3105</td><td>Sami Okoro</td><td><span class="badge text-bg-secondary">Refunded</span></td><td class="text-end">$48.00</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3104</td><td>Mia Lund</td><td><span class="badge text-bg-warning">Pending</span></td><td class="text-end">$129.90</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3103</td><td>Raj Patel</td><td><span class="badge text-bg-danger">Overdue</span></td><td class="text-end">$275.00</td></tr>
        <tr class="bsr-tbl-row"><td class="d-none d-sm-table-cell">#3102</td><td>Cleo Marsh</td><td><span class="badge text-bg-success">Paid</span></td><td class="text-end">$92.40</td></tr>
        <tr class="d-none bsr-tbl-empty"><td colspan="4" class="text-center text-body-secondary py-4">No orders match <span class="fw-semibold bsr-tbl-term"></span></td></tr>
      </tbody>
    </table>
  </div>
  <p class="small text-body-secondary px-3 py-2 mb-0 border-top bsr-tbl-count" role="status">Showing 7 of 7 orders</p>
</div>

Search with recent searches

  • dropdown-menu
  • dropdown-item
  • input-group
  • focusout

Click the field, pick or remove a recent search.

Focus the field and a panel styled with .dropdown-menu lists your recent searches, each with a remove button that has its own aria-label. The list lives in a plain array in memory, so it resets on reload and stores nothing. Submitting moves the term to the top, and the panel closes when focus leaves the search area.

View code
<div class="bsr-recent w-100">
  <form class="bsr-recent-form" role="search" aria-label="Shop search">
    <label for="bsr-recent-q" class="form-label fw-bold">Search the shop</label>
    <div class="position-relative bsr-recent-wrap">
      <div class="input-group">
        <input id="bsr-recent-q" type="search" class="form-control" placeholder="Desks, lamps, cables" autocomplete="off" aria-controls="bsr-recent-panel">
        <button class="btn btn-dark bsr-recent-go" type="submit" aria-label="Search"><i class="bi bi-search" aria-hidden="true"></i></button>
      </div>
      <div class="dropdown-menu w-100 p-2 shadow bsr-recent-panel" id="bsr-recent-panel">
        <div class="d-flex justify-content-between align-items-center px-2 pb-1">
          <h2 class="small fw-semibold text-body-secondary mb-0" id="bsr-recent-title">Recent searches</h2>
          <button type="button" class="btn btn-link btn-sm p-0 bsr-recent-clear">Clear all</button>
        </div>
        <ul class="list-unstyled mb-0 bsr-recent-list" aria-labelledby="bsr-recent-title"></ul>
      </div>
    </div>
  </form>
  <p class="small text-body-secondary mt-2 mb-0 bsr-recent-out" role="status">Your last searches appear when you focus the field.</p>
</div>

Instant results with thumbnails

  • list-group-flush
  • object-fit-cover
  • mark
  • aria-describedby

Type road, snow or canyon.

A travel guide search that narrows a flush list group of linked results while you type. Thumbnails use the 5.3 object-fit-cover utility and an empty alt, because the title next to them already says what they show. The matching part of each title is rebuilt with a mark element, and the count line is tied to the input with aria-describedby.

View code
<div class="bsr-dest w-100 bg-body border rounded-4 shadow-sm p-3 p-sm-4">
  <search>
    <label for="bsr-dest-q" class="form-label fw-bold fs-5">Where to next?</label>
    <input id="bsr-dest-q" type="search" class="form-control form-control-lg bsr-dest-input" placeholder="Try road, snow or canyon" autocomplete="off" aria-describedby="bsr-dest-count">
  </search>
  <p class="small text-body-secondary mt-2 mb-1 bsr-dest-count" id="bsr-dest-count" role="status">6 guides</p>
  <div class="list-group list-group-flush bsr-dest-list">
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="fjord.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">Fjord country by ferry</span><span class="small text-body-secondary">9 days, slow travel</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="red-rock-canyon.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">Red rock canyon loop</span><span class="small text-body-secondary">6 days, hiking</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="highland-road.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">Highland road trip</span><span class="small text-body-secondary">7 days, driving</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="canal-houses.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">Canal towns on foot</span><span class="small text-body-secondary">4 days, city walks</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="snow-camp.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">First night of snow camping</span><span class="small text-body-secondary">2 days, winter</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
    <a href="#" class="list-group-item list-group-item-action d-flex align-items-center gap-3 px-2 bsr-dest-item">
      <img src="coast-road.webp" alt="" width="64" height="48" class="rounded-2 object-fit-cover flex-shrink-0">
      <span class="flex-grow-1"><span class="d-block fw-semibold bsr-dest-name">Cliff-top coast road</span><span class="small text-body-secondary">5 days, driving</span></span>
      <i class="bi bi-chevron-right text-body-secondary" aria-hidden="true"></i>
    </a>
  </div>
  <p class="mb-0 mt-2 text-body-secondary d-none bsr-dest-empty">No guides match yet. Try a landscape such as coast or canyon.</p>
</div>

Themed and app-style search boxes

Dark mode, a fully re-themed pill box built from the 5.3 CSS variables, and the search bar of a mail app with an options dropdown that writes filter operators into the query.

Dark console search with a scope dropdown

  • data-bs-theme="dark"
  • input-group
  • dropdown-toggle
  • aria-current

Pick a scope, type and press Enter.

An admin console in dark mode puts a dropdown button inside the input group to pick what the search covers. The toggle keeps a visually-hidden prefix so screen readers hear the current scope in context, the chosen item gets .active and aria-current, and the submit button is re-colored with the --bs-btn-* variables.

View code
<form class="bsr-scope w-100 p-3 p-sm-4 rounded-4" role="search" aria-label="Console search">
  <label for="bsr-scope-q" class="form-label fw-semibold">Search the console</label>
  <div class="input-group">
    <button class="btn btn-outline-secondary dropdown-toggle bsr-scope-btn" type="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Search in: </span><span class="bsr-scope-label">Everything</span></button>
    <ul class="dropdown-menu bsr-scope-menu">
      <li><button type="button" class="dropdown-item active" aria-current="true" data-bsr-scope="Everything">Everything</button></li>
      <li><button type="button" class="dropdown-item" data-bsr-scope="Users">Users</button></li>
      <li><button type="button" class="dropdown-item" data-bsr-scope="Invoices">Invoices</button></li>
      <li><button type="button" class="dropdown-item" data-bsr-scope="Logs">Logs</button></li>
    </ul>
    <input type="search" class="form-control" id="bsr-scope-q" placeholder="Name or ID" autocomplete="off">
    <button class="btn bsr-scope-go" type="submit" aria-label="Search"><i class="bi bi-search" aria-hidden="true"></i></button>
  </div>
  <div class="d-flex justify-content-between gap-3 mt-2 small text-body-secondary">
    <span class="bsr-scope-out" role="status">Choose a scope, then search.</span>
    <span class="d-none d-sm-inline text-nowrap"><kbd>Enter</kbd> to search</span>
  </div>
</form>

Themed pill search with a loading state

  • --bs-border-radius
  • --bs-btn-* variables
  • spinner-border-sm
  • aria-busy

Use the controls next to the input.

A secondhand bookshop theme made almost entirely from variables: setting --bs-border-radius and --bs-border-radius-lg to 50rem on the form turns the whole input group into a pill, and the button colors come from --bs-btn-*. On submit the button shows a spinner-border-sm, the form gets aria-busy, and the result line updates when the fake request ends.

View code
<form class="bsr-book w-100 p-3 p-sm-4 rounded-4" role="search" aria-label="Catalogue search">
  <label for="bsr-book-q" class="form-label fw-bold bsr-book-label">Search 18,000 used books</label>
  <div class="input-group input-group-lg">
    <span class="input-group-text"><i class="bi bi-book" aria-hidden="true"></i></span>
    <input id="bsr-book-q" type="search" class="form-control" placeholder="Title or author" autocomplete="off">
    <button type="submit" class="btn bsr-book-btn"><span class="spinner-border spinner-border-sm me-2 d-none bsr-book-spin" aria-hidden="true"></span><span class="bsr-book-text">Search</span></button>
  </div>
  <p class="mt-3 mb-0 bsr-book-out" role="status">Free shipping on orders of three books or more.</p>
</form>

Mail search with an options dropdown

  • data-bs-auto-close="outside"
  • dropdown-menu-end
  • form-check
  • Dropdown API

Open the options, fill them and press Add to search.

A sliders button at the end of the input group opens a dropdown with a small form. data-bs-auto-close="outside" keeps the menu open while you fill it, and Add to search turns the fields into from:, newer_than: and has: operators in the query, replaces any old ones, then closes the menu with the Dropdown API.

View code
<form class="bsr-mail w-100" role="search" aria-label="Mail search">
  <div class="input-group shadow-sm rounded-3">
    <span class="input-group-text bg-body"><i class="bi bi-search" aria-hidden="true"></i></span>
    <input type="search" id="bsr-mail-q" class="form-control" aria-label="Search mail" placeholder="Search mail" autocomplete="off">
    <button type="button" class="btn btn-outline-secondary bsr-mail-opts" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" aria-label="Search options"><i class="bi bi-sliders" aria-hidden="true"></i></button>
    <div class="dropdown-menu dropdown-menu-end p-3 shadow bsr-mail-menu">
      <div class="mb-2">
        <label for="bsr-mail-from" class="form-label small fw-semibold">From</label>
        <input type="text" class="form-control form-control-sm" id="bsr-mail-from" placeholder="name@example.com" autocomplete="off">
      </div>
      <div class="mb-2">
        <label for="bsr-mail-within" class="form-label small fw-semibold">Date within</label>
        <select class="form-select form-select-sm" id="bsr-mail-within">
          <option value="">Any time</option>
          <option value="7d">1 week</option>
          <option value="1m">1 month</option>
          <option value="1y">1 year</option>
        </select>
      </div>
      <div class="form-check mb-3">
        <input class="form-check-input" type="checkbox" id="bsr-mail-att">
        <label class="form-check-label" for="bsr-mail-att">Has attachment</label>
      </div>
      <button type="button" class="btn btn-primary btn-sm w-100 bsr-mail-apply">Add to search</button>
    </div>
  </div>
  <p class="small text-body-secondary mt-2 mb-0 bsr-mail-out" role="status">Use the options button to build a filter query.</p>
</form>

What Is a Bootstrap Search Box?

Bootstrap doesn’t ship a search component. Nothing in the Bootstrap framework carries that name. The box is ordinary form markup that Bootstrap styles, and it needs no custom CSS.

Query handling, results display, filtering and autocomplete all sit outside the markup, and Bootstrap has no JavaScript plugin for any of them.

Results come from somewhere else. A form action can point at a backend script, or JavaScript can filter content that’s already on the page. Hosted search services are the other route.

Directory and service sites often give the box a larger spot of its own.

How Do You Write the HTML for a Bootstrap Search Box?

You need a form, an input with type=”search” and a submit button. Bootstrap’s form-control and btn classes style them, and d-flex on the form keeps the two on one row.

For the query to reach the server, the form needs an action and method=”get”, and the input needs a name. Skip the name and the browser submits nothing for that field.

With method=”get”, the query lands in the URL as ?q=term, which also makes result pages linkable.

Standalone input and button with d-flex

This follows the form example in the Bootstrap 5.3 navbar documentation, with an action and a name added.

<form class="d-flex" role="search" action="/search" method="get">
  <input class="form-control me-2" type="search" name="q" placeholder="Search" aria-label="Search">
  <button class="btn btn-outline-success" type="submit">Search</button>
</form>

The role=”search” attribute marks the form as a search landmark. me-2 is the gap between input and button. As for btn-outline-success, that’s only the button style, and any btn variant can replace it.

Bootstrap’s input styling makes the field full width, pads it, and adds a focus state. Drop d-flex and the button falls below the input, because form-control is a block-level element.

Input group version

An input group joins the field and the button into one block with shared edges.

<form action="/search" method="get" role="search">
  <div class="input-group">
    <input type="search" name="q" class="form-control" placeholder="Search" aria-label="Search">
    <button class="btn btn-primary" type="submit">Search</button>
  </div>
</form>

Bootstrap’s input group documentation says labels belong outside the group. A visible label goes above it, and aria-label covers the input when no label shows.

The markup is plain HTML, so any server-side template renders it unchanged.

My habit is the input group for anything with an icon or a spot in a form column, and plain d-flex inside a navbar.

How to Add a Bootstrap Search Box to a Navbar, Modal or Offcanvas Panel

The navbar is the default home, and the form goes inside .navbar-collapse. Modals take it in .modal-body and offcanvas panels in .offcanvas-body, which suits overlay search and phone layouts.

PlacementContainer classOpens withBest for
Navbar.navbar-collapse.navbar-toggler below the expand breakpointPersistent site header
Modal.modal-bodyButton with data-bs-toggle=”modal”Full overlay search
Offcanvas.offcanvas-bodyButton with data-bs-toggle=”offcanvas”Side panel on phones

Navbar

Bootstrap’s navbar component collapses responsively only when .navbar carries an expand class such as .navbar-expand-lg. The .navbar-collapse wrapper holds whatever hides behind the toggler (Bootstrap 5.3 documentation).

With the lg suffix, the collapse happens below 992px.

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="/">Brand</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navSearch" aria-controls="navSearch" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navSearch">
      <form class="d-flex ms-auto" role="search" action="/search">
        <input class="form-control me-2" type="search" name="q" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>

The usual mistake is putting the form outside .navbar-collapse. It never hides, so on a phone it sits in the row with the brand and the toggler.

Modal and offcanvas

In a Bootstrap modal the autofocus attribute has no effect, so listen for shown.bs.modal and call focus() on the input yourself (Bootstrap documentation).

const modal = document.getElementById('searchModal')
  const input = document.getElementById('modalSearch')
  modal.addEventListener('shown.bs.modal', () => input.focus())

Offcanvas has no default placement, so add .offcanvas-start, .offcanvas-end, .offcanvas-top or .offcanvas-bottom.

Responsive classes such as .offcanvas-lg arrived in Bootstrap 5.2.0. Below the lg breakpoint the content slides in as a panel, and above it the same markup renders as normal page content.

Outside those containers, the form goes in a .container and takes a column class such as .col-md-6.

How Do You Control the Width and Size of a Bootstrap Search Box?

Grid columns and width utilities handle width, with a max-width cap when you need one. Height comes from the form sizing classes.

In practice, col-* classes on a wrapper set the width relative to the row, while w-25, w-50, w-75, w-100 and w-auto set it relative to the parent. mw-100 caps the box at the parent width. Height is the job of form-control-lg and form-control-sm.

Width and centering

The width utilities in Bootstrap’s own sizing documentation come in 25%, 50%, 75%, 100% and auto.

To center the box, wrap it in a row with justify-content-center and a column such as col-md-6, or give the form w-50 and mx-auto. The grid system handles the width, so the input needs no extra class.

For a full-width bar, set w-100 on the form or the input group and place it inside a container-fluid.

Size classes

ClassGoes onResult
form-control-lgThe inputTaller field, larger text
form-control-smThe inputShorter field, smaller text
input-group-lg.input-groupInput and button grow together
input-group-sm.input-groupInput and button shrink together

Add the size class to the .input-group itself and the contents resize with it. Repeating form-control-lg on each child is unnecessary.

Showing the box at one breakpoint only

Display utilities let you hide the full box below a breakpoint and show it above.

Bootstrap defines six default breakpoints, from extra small (under 576px) to xxl (1400px and up), per its breakpoints documentation.

On the small side, put d-lg-none on a compact button that opens a modal or offcanvas panel. From lg up, the full form gets d-none d-lg-flex.

Use d-lg-flex, not d-lg-block, so the form keeps its flex layout. The swap follows standard responsive design practice: a small trigger on phones, the full field where there is room.

Adding a Search Icon and Styling the Box

The icon goes in an .input-group-text addon next to the input, using bi-search from Bootstrap Icons or the matching class from Font Awesome.

Bootstrap Icons offers the search glyph both as a downloadable SVG and as an icon-font class (bi bi-search), per its icon page.

<div class="input-group">
  <span class="input-group-text" id="search-addon"><i class="bi bi-search"></i></span>
  <input type="search" class="form-control" placeholder="Search" aria-label="Search" aria-describedby="search-addon">
</div>

I’d take inline SVG over the icon font when the search icon is the only icon on the page. One glyph should not cost a font download.

For shape, .rounded-pill reads $border-radius-pill, which defaults to 50rem in Bootstrap 5.3. On a standalone input that works directly.

A pill-shaped box with an attached icon or button is a Sass job. Set $input-border-radius to 50rem, then check the joined edge in the browser.

For colors, $input-border-color sets the resting border and $input-focus-border-color handles focus. The focus default is tint-color($component-active-bg, 50%), and $component-active-bg is $primary.

@import "bootstrap/scss/functions";

  $input-border-radius: 50rem;
  $input-focus-border-color: #198754;

  @import "bootstrap/scss/bootstrap";

Any replacement color needs enough color contrast against the page background, or the focus state disappears for low-vision users.

These variables change every form control on the site, not only the search box. Scope the change with a custom class when other forms must keep the defaults.

How to Make a Bootstrap Search Box Accessible

The input’s name is where most search boxes fail. The rest is a unique label when a page holds more than one search region, a visible focus state, and real text inside any icon-only button.

Name the input

WCAG 2.2 success criterion 4.1.2 (Level A) requires a programmatically determinable name for every interface component, and the W3C’s Understanding document allows that name to be invisible.

Two W3C examples show the range. The ARIA Authoring Practices search example uses aria-label alone. WCAG technique H44 goes the other way and pairs the input with a visible label element.

For a Bootstrap search box, a label hidden with visually-hidden keeps the compact look and still gives screen readers a real label element. The placeholder never replaces it, because MDN calls the placeholder a weaker way to explain a field.

<label for="site-q" class="visually-hidden">Search the site</label>
<input id="site-q" class="form-control" type="search" name="q" placeholder="Search">

The same naming rules run through the wider guidance on accessible forms, and the search field is no exception.

Two search boxes on one page

A navbar box plus a modal or in-page filter puts two search regions on one page, and each needs its own name.

The ARIA authoring guidance asks for a unique label on every search landmark when a page has more than one.

On a form with role=”search”, add a distinct aria-label, such as “Site search” and “Catalog search”. The native search element carries the landmark without the role attribute.

The search element became Baseline newly available on 2023-10-13, with support from Chrome 118, Firefox 118, Edge 118 and Safari 17, and the web-features project set 2026-04-13 as its Widely available date (web-features project). Bootstrap’s own navbar examples still use role=”search”, so keep that attribute when the site must serve older browsers.

Icon-only buttons and focus

An icon-only submit button has no name until text sits inside it. Bootstrap’s badge examples use the same fix, hidden text in a span with visually-hidden.

<button class="btn btn-primary" type="submit">
  <i class="bi bi-search" aria-hidden="true"></i>
  <span class="visually-hidden">Search</span>
</button>

WCAG 2.2 criterion 2.4.7 (Focus Visible) requires a visible keyboard focus indicator. Bootstrap draws the form-control focus state with $input-focus-border-color and $input-focus-box-shadow rather than the browser outline, so custom CSS that sets box-shadow: none removes it.

An easy check is to press Tab to the field, then to the button. If you can’t see where focus sits, the style is gone.

What Changed in Bootstrap 5 Search Box Markup Compared With Bootstrap 4?

Moving a search box from Bootstrap 4 to 5 means swapping a handful of classes and attributes.

Bootstrap 4Bootstrap 5Where it shows up
form-inlined-flex on the formOne-row layout
input-group-append, input-group-prependButton or addon as a direct child of .input-groupAttached search button
mr-2, ml-2me-2, ms-2Gap between input and button
data-toggle, data-targetdata-bs-toggle, data-bs-targetNavbar toggler, modal trigger
sr-onlyvisually-hiddenHidden label text

Three of those are plain renames. form-inline and the append and prepend wrappers are the ones that need markup changes.

Bootstrap’s v5 migration guide points inline forms toward the grid, while the navbar documentation uses d-flex. For a single input and button, d-flex is the lighter option.

Paste a Bootstrap 4 box into a Bootstrap 5 page and it loses its one-row layout and its toggles, because form-inline no longer exists and the plugins respond only to data-bs-* attributes.

The migration guide also records that jQuery is gone, so any jQuery code bundled with a snippet runs only if you load the library yourself. Labels gain a requirement too. v5 expects the form-label class, which the Bootstrap form components cover in full.

How to Make a Bootstrap Search Box Actually Search

Match the method to where the content lives. A JavaScript filter works when the content is already on the page. Anything in a database needs a form submit to a server, and a documentation site can get by with a hosted index.

Which search method fits the project

MethodNeeds a serverBest fitMain limit
JavaScript filterNoTables, lists and card grids already on the pageSearches only what is rendered
datalist suggestionsNoA short, fixed list of termsBrowser draws the list, no styling
Form submit to a serverYesDatabase or catalog contentPage reload unless fetched with script
Hosted indexNo (hosted)Documentation, site-wide searchEligibility, ads or fees by service

Bootstrap’s own documentation uses Algolia DocSearch, according to the Bootstrap README. DocSearch is free for developer documentation and technical blogs, so a store or portfolio site does not qualify.

In the end the content decides which method you use.

Build a live filter in plain JavaScript

  1. Give each searchable element a shared hook such as data-filter-item, and give the input an id.
  2. Listen for the input event, which fires on every keystroke.
  3. Lowercase the query and each item’s text, then compare with includes().
  4. Toggle Bootstrap’s d-none class on items that do not match.
  5. Show a no-results message when every item is hidden.
const input = document.getElementById('filter-q')
const items = document.querySelectorAll('[data-filter-item]')

input.addEventListener('input', () => {
  const q = input.value.trim().toLowerCase()
  items.forEach(el => {
    el.classList.toggle('d-none', !el.textContent.toLowerCase().includes(q))
  })
})

A handful of lines of JavaScript does the work, and Bootstrap’s d-none class does the hiding.

A form holding one text field submits on Enter and reloads the page. A JavaScript-only filter needs neither a form nor a submit button, so dropping the form is the simplest fix.

Autocomplete suggestions

With datalist, you link the input to it through the list attribute and the browser draws the suggestions.

<input class="form-control" type="search" name="q" list="suggestions" aria-label="Search">
<datalist id="suggestions">
  <option value="Buttons">
  <option value="Modals">
</datalist>

MDN says the values are suggestions, not requirements. It also warns that some screen reader and browser pairs, NVDA with Firefox among them, do not announce the popup contents, and that the list cannot be styled for high-contrast mode.

A menu fed by script gives full styling control. With a Bootstrap dropdown, the keyboard and ARIA behavior of a combobox is yours to build.

When the list is too long to ship in the page, either approach can talk to a server through the Fetch API. fetch(‘/suggest?q=’ + encodeURIComponent(q)) returns JSON to render.

When a Bootstrap Search Box Is the Wrong Choice

A Bootstrap search box works until the content outgrows the page or users expect ranked results. Browser quirks in the search input can get in the way too.

Client-side filtering on large lists

Lighthouse warns when the body element has more than about 800 nodes and reports an error above about 1,400, according to Chrome’s documentation.

A filter only hides rows that already exist, so every row stays in the DOM. At seven elements per row, the warning threshold arrives at roughly 115 rows, before counting the rest of the page.

Past that range, send the query to a server or render only the visible page of results. Lighthouse’s own advice is to create DOM nodes only when they are needed.

Ranking, typo tolerance and facets

Bootstrap gives you an input and a button, and nothing about search quality. includes() returns matches in page order, not by relevance. Typos match nothing at all. Facets like category or price are extra work, with their own controls and logic.

When users expect those, a server-side or hosted engine does the work and the Bootstrap box stays as the front end.

Browser differences in the search input

MDN says browsers handle type=”search” differently from type=”text”. Chromium draws an x icon inside the field. Firefox draws none, because its clear-button layout still sits behind a preference that is off by default.

Escape clears a search field in Chrome, and Firefox 141 added the same behavior (Mozilla Bugzilla bug 1055085).

If a clear control belongs in the design, build the button yourself and check it across engines for cross-browser compatibility.

Hosted search services and their deadlines

As of October 2026, Google’s Custom Search JSON API is closed to new customers and retires on January 1, 2027 (Google’s Programmable Search Engine documentation).

On Programmable Search Engine, new engines cannot enable “Search the entire web”, and existing engines keep it until the same date. The free search element is ad-supported, and the ad-free version costs $5 per 1,000 queries.

A site that does not qualify for DocSearch can start on Algolia’s free plan, which includes 50,000 records and 10,000 search requests a month according to Algolia’s pricing page, so a large or busy site may need a paid plan.

Check these terms before wiring a Bootstrap box to either service.

A site that does not load Bootstrap anywhere else gains little from adding it for one input. A hand-written CSS search box does the same job with a few rules.

Bootstrap Search Box FAQ

How do I add a clear button to the search field?

Place a button with type=”button” after the input inside the input group. On click, set the input value to an empty string and call focus() on the field.

On a live filter, also dispatch an input event so the list resets.

Can I put a category dropdown next to the input?

Yes. Add a select with the form-select class as the first child of the input group, before the input.

Give it an aria-label such as “Category” and read its value on submit as a second query parameter.

How do I change the placeholder color?

Target the pseudo-element with a rule like .form-control::placeholder and set its color. In a Sass build, $input-placeholder-color does the same before the Bootstrap import.

Keep the result readable. A pale placeholder on a white field is hard to see.

Where can I find free Bootstrap search box templates?

Colorlib publishes free search form templates, and Bootsnipp and CodePen host community snippets.

Check the license on each one. Confirm the snippet targets Bootstrap 5 too, because many older snippets rely on classes that version removed.

What to Test Before Launching a Bootstrap Search Box

Before launch, check keyboard and screen reader access first, then whether a query actually reaches the results page, then the layout at narrow widths.

That order follows how many visitors a failure affects. A missing accessible name blocks every assistive technology user, a dropped query breaks every search, and a narrow-width fault hits one viewport.

The cost is time. Manual keyboard and screen reader passes run slower than a visual check, and they still come first.

A fuller web accessibility checklist carries the first pass beyond the search field to the rest of the page.