Search Input

Search field variants: icon, clear button, expanding focus, keyboard shortcut badge, and instant results preview.

Default with Icon

DaisyUI's input inside an label wrapper handles the icon-left pattern natively. Three sizes available: input-xs, input-sm, input-md.

Extra small

Small

Medium (default)

Large

<label class="input input-sm input-bordered w-full">
  <i data-lucide="search" class="w-4 h-4 opacity-50"></i>
  <input type="search" placeholder="Search…" />
</label>

With Clear Button

An × button appears once the field has a value, dismissing the query on click and returning focus to the input. Alpine drives visibility — no custom CSS needed.

Clearable (type something)

i.toLowerCase().includes(s)); } }">

Clear + result count badge

<div x-data="{ q: '' }">
  <label class="input input-sm input-bordered w-full">
    <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
    <input type="search" placeholder="Search…"
           x-model="q" autocomplete="off"/>
    <button x-show="q.length > 0" x-cloak
            @click="q = ''; $nextTick(() =>
              $el.closest('label').querySelector('input').focus())"
            class="btn btn-ghost btn-xs btn-circle"
            aria-label="Clear search" type="button">
      <i data-lucide="x" class="w-3 h-3"></i>
    </button>
  </label>
</div>

Expanding on Focus

Compact by default (160 px), expands to full container width on focus-within. Width transitions via .si-expand which cannot be expressed as a Tailwind static class because the start and end values depend on context. Ideal for toolbar search that shares space with other controls.

Products

Click the search field to see it expand

<!-- .si-expand: width:10rem, expands to 100% on focus-within -->
<div class="si-expand" x-data="{ q: '' }">
  <label class="input input-sm input-bordered w-full">
    <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
    <input type="search" placeholder="Search…"
           x-model="q" autocomplete="off"/>
    <button x-show="q.length > 0" x-cloak @click="q = ''"
            class="btn btn-ghost btn-xs btn-circle"
            type="button" aria-label="Clear">
      <i data-lucide="x" class="w-3 h-3"></i>
    </button>
  </label>
</div>

<!-- CSS (in /css/ui/design-system/layout.css or similar) -->
<style>
.si-expand {
  width: 10rem;
  transition: width 250ms cubic-bezier(0,0,0.2,1);
}
.si-expand:focus-within { width: 100%; }
</style>

Keyboard Shortcut Badge

Displays the keyboard hint (⌘K / Ctrl K) inside the field when idle. Pressing the shortcut focuses the input; Escape blurs it. The badge is absolutely positioned inside the wrapper — requires .si-kbd-wrap custom CSS to compensate the input's right padding.

Press to focus

K

Press / to focus

/
<div x-data="{ q: '', focused: false, isMac: navigator.platform.includes('Mac') }"
     x-init="window.addEventListener('keydown', e => {
       if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
         e.preventDefault(); $refs.input.focus();
       }
       if (e.key === 'Escape' && focused) $refs.input.blur();
     })">

  <div class="si-kbd-wrap">
    <label class="input input-sm input-bordered w-full">
      <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
      <input type="search" placeholder="Quick search…"
             x-model="q" x-ref="input"
             @focus="focused = true" @blur="focused = false"/>
    </label>

    <div class="si-kbd-badge"
         x-show="!focused && q.length === 0" x-cloak>
      <kbd class="kbd kbd-xs" x-text="isMac ? '⌘' : 'Ctrl'"></kbd>
      <kbd class="kbd kbd-xs">K</kbd>
    </div>
  </div>
</div>

Instant Results Preview

A dropdown panel appears below the input as the user types, showing filtered results grouped by category. Arrow keys move focus, Enter selects, Escape closes. The highlight marks the matched substring. In production, replace the static array with a debounced fetch call.

<div x-data="{
  q: '', open: false, cursor: -1,
  catalog: [ /* { cat, icon, label, meta } */ ],
  get results() {
    if (!this.q.trim()) return [];
    const s = this.q.toLowerCase();
    return this.catalog.filter(i => i.label.toLowerCase().includes(s));
  },
  get groups() {
    const g = {};
    this.results.forEach(i => { (g[i.cat] ??= []).push(i); });
    return g;
  },
  onKey(e) {
    if (e.key === 'ArrowDown') { e.preventDefault(); this.cursor = Math.min(this.cursor+1, this.results.length-1); }
    if (e.key === 'ArrowUp')   { e.preventDefault(); this.cursor = Math.max(this.cursor-1, -1); }
    if (e.key === 'Escape')    { this.open = false; this.q = ''; }
  }
}" @keydown="onKey($event)" @click.outside="open = false">

  <label class="input input-sm input-bordered w-full">
    <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
    <input type="search" placeholder="Search…"
           x-model="q" autocomplete="off"
           @input="open = q.length > 0; cursor = -1"
           @focus="open = q.length > 0"
           role="combobox" :aria-expanded="open"/>
    <button x-show="q.length > 0" x-cloak @click="q='';open=false"
            class="btn btn-ghost btn-xs btn-circle"
            type="button" aria-label="Clear">
      <i data-lucide="x" class="w-3 h-3"></i>
    </button>
  </label>

  <div class="si-results" x-show="open" x-cloak role="listbox">
    <template x-for="(items, cat) in groups" :key="cat">
      <div>
        <div class="si-result-divider" x-text="cat"></div>
        <template x-for="item in items" :key="item.label">
          <button class="si-result-item" role="option"
                  @click="q = item.label; open = false">
            <i :data-lucide="item.icon" class="si-result-icon"></i>
            <span x-text="item.label"></span>
            <span class="si-result-meta" x-text="item.meta"></span>
          </button>
        </template>
      </div>
    </template>
  </div>
</div>

States

Error and disabled states follow DaisyUI's input-error modifier and the native disabled attribute respectively. Loading uses a spinner in the suffix slot.

Default

Error

Special characters are not allowed.

Disabled

Loading

With voice input icon

<!-- Error -->
<label class="input input-sm input-bordered input-error w-full">
  <i data-lucide="search" class="w-4 h-4 opacity-50"></i>
  <input type="search" value="??invalid##"/>
</label>
<p class="text-error text-xs mt-1">Special characters are not allowed.</p>

<!-- Disabled -->
<label class="input input-sm input-bordered w-full opacity-50 cursor-not-allowed">
  <i data-lucide="search" class="w-4 h-4 opacity-50"></i>
  <input type="search" placeholder="Search…" disabled/>
</label>

<!-- Loading -->
<label class="input input-sm input-bordered w-full">
  <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
  <input type="search" value="headphones" readonly/>
  <span class="loading loading-spinner loading-xs text-base-content/40"></span>
</label>