Search input
A pill-shaped input with a leading search icon and a clear button that appears when the field has a value. Used for filtering expense lists, finding members, and searching categories. The glass variant floats over content in the nav bar.
Variants
Standard
With value (clear button visible)
3 results
Mono text label
No results
No results — try "GPay" or "PhonePe"
Standard — pill-shaped, 44px height, leading SVG search icon. Border transitions to teal on focus. Used in expense list screens, member pickers, category search.
Mono text label — the word "search" in JetBrains Mono replaces the SVG icon. Use when the icon might be confused with another affordance, or for a more typographic feel.
Clear button — appears only when the field has a value. 24px circle with ×. Disappears when field is empty. Never show it in the empty state.
Glass variant
The glass variant uses backdrop-filter: blur(12px) and a translucent background. Used in the nav bar when it floats over a colored or image header. On focus, it becomes more opaque to improve readability.
Sizes
| Size | Height | Font | Icon | Use case |
|---|---|---|---|---|
| Small | 36px | 13px | 14px | Compact filter bars inside sheets |
| Default | 44px | 15px | 16px | Standard — expense list, member picker |
| Large | 52px | 17px | 18px | Full-screen search, home screen prominence |
States
Empty (resting)
Focused (typing)
With value (results)
7 expenses
No results
No results
| State | Border | Icon | Clear |
|---|---|---|---|
| Empty | --ink-line | Muted | Hidden |
| Focused | --teal + teal glow | Teal | Hidden |
| Has value | --ink-line | Muted | Visible |
| No results | --coral | Muted | Visible |
| Disabled | --ink-line | 40% opacity | Hidden |
On dark surfaces
Anatomy
| Part | Element | Notes |
|---|---|---|
| Wrapper | div.search-wrap | Relative position. Gets .has-value class when field is non-empty to show clear button. |
| Leading icon | SVG or span.search-icon--text | Absolutely positioned at left:14px. Pointer-events off — not interactive. |
| Input | input[type=search].search-input | Pill shape. Padding-left accounts for icon width. |
| Clear button | button.search-clear | Absolutely positioned at right:12px. Hidden when field is empty. Needs aria-label="Clear search". |
| Hint | p.search-hint | Optional below-field text. Use for result count or no-results message. |
Usage
Accessibility
Tab focuses the input. Escape should clear the field and optionally dismiss the search context. The clear button is reachable via Tab when visible. Enter does nothing in live-search — the list already filtered.
type="search" — screen readers announce "search field." Add aria-label describing the search context ("Search expenses", "Find a member"). The clear button needs aria-label="Clear search". Result count hint should be a live region: aria-live="polite".
aria-live hint element so it's announced when it appears.
Code
HTML
<!-- Standard search input --> <div class="search-wrap"> <svg class="search-icon" width="16" height="16" aria-hidden="true" viewBox="0 0 16 16" fill="none"> <circle cx="7" cy="7" r="5" stroke="currentColor" stroke-width="1.5"/> <path d="M11 11l2.5 2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> </svg> <input class="search-input" type="search" placeholder="Search expenses…" aria-label="Search expenses" autocomplete="off"> <button class="search-clear" aria-label="Clear search">×</button> </div> <p class="search-hint" aria-live="polite"></p> <!-- Glass variant --> <div class="search-wrap"> <!-- ... icon ... --> <input class="search-input search-input--glass" type="search" placeholder="Search…" aria-label="Search"> </div>
JS pattern (clear button)
// Toggle .has-value on the wrapper const wrap = document.querySelector('.search-wrap'); const input = wrap.querySelector('.search-input'); const clear = wrap.querySelector('.search-clear'); input.addEventListener('input', () => { wrap.classList.toggle('has-value', input.value.length > 0); }); clear.addEventListener('click', () => { input.value = ''; wrap.classList.remove('has-value'); input.focus(); });
CSS classes
| Class | Purpose |
|---|---|
.search-wrap | Position: relative wrapper for icon + input + clear |
.search-wrap.has-value | Makes clear button visible |
.search-input | Pill input, 44px, teal focus ring |
.search-input--glass | Frosted glass variant for nav bar |
.search-icon | Absolute leading icon |
.search-icon--text | Mono text "search" label variant |
.search-clear | Clear × button, hidden when empty |
.search-hint | Below-field result count or no-results message |
.search-hint--empty | No results — coral text |