Skip to component content

Add icons, text, buttons, and helper content to inputs with Bootstrap's native grouping behavior.

Usage

Use .input-group when a text input needs a tightly attached prefix, suffix, icon, button, or short addon. Put the editable control and its attached addons inside one group, and keep any visible label outside the group as Bootstrap recommends.

Keep the input as the primary control. Addons should clarify the value, such as a currency symbol, unit, search icon, domain suffix, or action button; avoid nesting unrelated controls that make the group hard to scan or tab through.

Input groups wrap by default to make validation possible. Apply size classes such as .input-group-sm or .input-group-lg to the group itself, not to each child, and be careful with hidden first or last children because they can affect Bootstrap's joined border radius.

Icon at start

Place a decorative icon in input-group-text before the input when it clarifies the field's purpose.

Input Group
Icon positioned at the start.
<div class="field w-100">
  <label class="form-label" for="icon-start-search">Input</label>
  <div class="input-group">
    <span class="input-group-text">
      <i class="lucide lucide-search" data-icon="inline-start" aria-hidden="true"></i>
    </span>
    <input class="form-control" id="icon-start-search" type="search" placeholder="Search..." aria-label="Search" aria-describedby="icon-start-search-help">
  </div>
  <div class="field-description form-text" id="icon-start-search-help">Icon positioned at the start.</div>
</div>

Icon at end

Place the addon after the input when the affordance belongs to the trailing edge.

Input Group
Icon positioned at the end.
<div class="field w-100">
  <label class="form-label" for="icon-end-password">Input</label>
  <div class="input-group">
    <input class="form-control" id="icon-end-password" type="text" placeholder="Enter password" aria-label="Password" aria-describedby="icon-end-password-help">
    <span class="input-group-text">
      <i class="lucide lucide-eye-off" data-icon="inline-start" aria-hidden="true"></i>
    </span>
  </div>
  <div class="field-description form-text" id="icon-end-password-help">Icon positioned at the end.</div>
</div>

Search results

Keep a result count in the same surface while the input remains the editable control.

Input Group
12 results
<div class="field w-100">
  <div class="input-group">
    <span class="input-group-text">
      <i class="lucide lucide-search" data-icon="inline-start" aria-hidden="true"></i>
    </span>
    <input class="form-control" type="search" placeholder="Search..." aria-label="Search results">
    <span class="input-group-text">12 results</span>
  </div>
</div>

Text

Input Group
$ USD
https:// .com
@company.com
120 characters left
<div class="field-group w-100">
  <div class="field">
    <div class="input-group">
      <span class="input-group-text">$</span>
      <input class="form-control" type="text" placeholder="0.00" aria-label="Amount">
      <span class="input-group-text">USD</span>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <span class="input-group-text">https://</span>
      <input class="form-control" type="text" placeholder="example.com" aria-label="Site path">
      <span class="input-group-text">.com</span>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <input class="form-control" type="text" placeholder="Enter your username" aria-label="Work email">
      <span class="input-group-text">@company.com</span>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <textarea class="form-control" rows="2" placeholder="Enter your message" aria-label="Message"></textarea>
      <div data-align="block-end">
        <span class="input-group-text">120 characters left</span>
      </div>
    </div>
  </div>
</div>

Button

Input Group
https://
<div class="field-group w-100">
  <div class="field">
    <div class="input-group">
      <input class="form-control" type="text" placeholder="https://example.com/moo" aria-label="Profile URL">
      <button class="btn btn-ghost btn-icon border-0" type="button" aria-label="Copy profile URL">
        <i class="lucide lucide-copy" data-icon="inline-start" aria-hidden="true"></i>
      </button>
    </div>
  </div>
  <div class="field">
    <div class="input-group rounded-pill">
      <button class="btn btn-ghost btn-icon border-0" type="button" aria-label="About secure URLs" data-bs-toggle="popover" data-bs-title="Your connection is not secure." data-bs-content="You should not enter sensitive information on this site." data-bs-placement="bottom">
        <i class="lucide lucide-info" data-icon="inline-start" aria-hidden="true"></i>
      </button>
      <span class="input-group-text">https://</span>
      <input class="form-control" type="text" aria-label="Secure URL">
      <button class="btn btn-ghost btn-icon border-0" type="button" aria-label="Favorite URL" data-bs-toggle="button" aria-pressed="false">
        <i class="lucide lucide-star" data-icon="inline-start" aria-hidden="true"></i>
      </button>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <input class="form-control" type="search" placeholder="Type to search..." aria-label="Search">
      <button class="btn btn-ghost border-0" type="button">Search</button>
    </div>
  </div>
</div>

Kbd

Use a single keyboard hint in the trailing addon; avoid splitting one shortcut into separate visual controls.

Input Group
⌘K
<div class="field w-100">
  <div class="input-group">
    <input class="form-control" type="search" placeholder="Search commands..." aria-label="Command search">
    <span class="input-group-text">
      <kbd>⌘K</kbd>
    </span>
  </div>
</div>

Use an icon-only menu for file actions or a labeled menu when the input action needs a search scope.

Input Group

Spinner

Use compact loading indicators inside addons when the input value is waiting on async work.

Input Group
Searching workspace
Processing import
Processing...
Saving...
Saving changes
Please wait...
Refreshing data
<div class="field-group w-100">
  <div class="field">
    <div class="input-group">
      <input class="form-control" type="search" placeholder="Searching..." aria-label="Search workspace">
      <span class="input-group-text px-2">
        <div class="spinner spinner-sm" role="status">
          <i class="lucide lucide-loader-circle" data-icon="inline-start" aria-hidden="true"></i>
          <span class="visually-hidden">Searching workspace</span>
        </div>
      </span>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <span class="input-group-text gap-2">
        <div class="spinner spinner-sm" role="status">
          <i class="lucide lucide-loader-circle" data-icon="inline-start" aria-hidden="true"></i>
          <span class="visually-hidden">Processing import</span>
        </div>
        <span>Processing...</span>
      </span>
      <input class="form-control" type="text" value="Import queue" readonly aria-label="Processing import">
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <input class="form-control" type="text" value="Draft settings" readonly aria-label="Saving changes">
      <span class="input-group-text gap-2">
        <span>Saving...</span>
        <div class="spinner spinner-sm" role="status">
          <i class="lucide lucide-loader-circle" data-icon="inline-start" aria-hidden="true"></i>
          <span class="visually-hidden">Saving changes</span>
        </div>
      </span>
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <span class="input-group-text">
        <i class="lucide lucide-refresh-cw" data-icon="inline-start" aria-hidden="true"></i>
      </span>
      <input class="form-control" type="text" value="Refreshing data..." readonly aria-label="Refreshing data">
      <span class="input-group-text gap-2">
        <span>Please wait...</span>
        <div class="spinner spinner-sm" role="status">
          <i class="lucide lucide-loader-circle" data-icon="inline-start" aria-hidden="true"></i>
          <span class="visually-hidden">Refreshing data</span>
        </div>
      </span>
    </div>
  </div>
</div>

Block-start addons

Place a label-like addon above an input or textarea while keeping the control focusable.

Input Group
<div class="field-group w-100">
  <div class="field">
    <div class="input-group">
      <div data-align="block-start">
        <label class="input-group-text" for="block-start-input">Full Name</label>
      </div>
      <input class="form-control" id="block-start-input" type="text" placeholder="Enter your name" aria-label="Display name">
    </div>
  </div>
  <div class="field">
    <div class="input-group">
      <div data-align="block-start">
        <label class="input-group-text" for="block-start-textarea">script.js</label>
      </div>
      <textarea class="form-control" id="block-start-textarea" rows="3" placeholder="console.log(&#39;Hello, world!&#39;);" aria-label="Code snippet"></textarea>
    </div>
  </div>
</div>

Block-end input

Place a unit below the input when the supporting content belongs to the field.

Input Group
<div class="field w-100">
  <div class="input-group">
    <input class="form-control" id="block-end-input-control" type="text" placeholder="Enter amount" aria-label="Amount">
    <div data-align="block-end">
      <label class="input-group-text flex-grow-1" for="block-end-input-control">USD</label>
    </div>
  </div>
</div>

Block-end textarea

Keep a counter and action below the textarea when both belong to the field.

Input Group
<div class="field w-100">
  <div class="input-group">
    <textarea class="form-control" id="block-end-textarea-control" rows="3" placeholder="Write a comment..." aria-label="Comment"></textarea>
    <div class="d-flex align-items-center justify-content-between" data-align="block-end">
      <label class="input-group-text flex-grow-1" for="block-end-textarea-control">0/280</label>
      <button class="btn btn-primary" type="button">Post</button>
    </div>
  </div>
</div>

Custom Input

Combine a textarea and action in one Bootstrap input group.

Input Group
<div class="field w-100">
  <div class="input-group">
    <textarea class="form-control" rows="4" placeholder="Write a message..." aria-label="Custom message"></textarea>
    <div class="justify-content-end" data-align="block-end">
      <button class="btn btn-primary" type="button">Submit</button>
    </div>
  </div>
</div>

RTL

Use one compact search control across Arabic and Hebrew RTL examples, with English as the LTR comparison.

⌘K
<div dir="rtl">
  <div class="field w-100">
    <div class="input-group">
      <input class="form-control" id="input-group-rtl-arabic" type="search" placeholder="ابحث داخل المحادثة" aria-label="بحث">
      <span class="input-group-text">
        <kbd>⌘K</kbd>
      </span>
    </div>
  </div>
</div>
⌘K
<div dir="rtl">
  <div class="field w-100">
    <div class="input-group">
      <input class="form-control" id="input-group-rtl-hebrew" type="search" placeholder="חפש בצ&#39;אנל" aria-label="חיפוש">
      <span class="input-group-text">
        <kbd>⌘K</kbd>
      </span>
    </div>
  </div>
</div>
⌘K
<div dir="ltr">
  <div class="field w-100">
    <div class="input-group">
      <input class="form-control" id="input-group-rtl-english" type="search" placeholder="Search the channel" aria-label="Search">
      <span class="input-group-text">
        <kbd>⌘K</kbd>
      </span>
    </div>
  </div>
</div>

Component reference

Status
Accepted
Runtime
native HTML/CSS
Markup
Bootstrap/native HTML
Reference

For more addon combinations, see the Bootstrap Input group documentation.

Settings

Theme
Choose how Moo UI looks on this device.
Sidebar
Choose how the sidebar sits on the page.
Theme Builder
Tune catalog tokens and chart colors for this browser.
Base color
Theme color
Chart color
Heading font
Body font
Radius
Direction
Choose the reading direction. RTL flips the layout live.
Reset

Restore the default appearance.