Smart Search
for the open web
A lightweight, production-ready search input built with Custom Elements and Shadow DOM. Drop it into React, Vue, Svelte, Angular, or plain HTML — no framework required.
Basic
Set a datasource URL with a {{q}} placeholder and provide a
transformResponse function to map the API response. Type to search DummyJSON products.
<smart-search placeholder="Search products..." datasource="https://api.example.com/search?{{q}}" debounce="300" ></smart-search> <script type="module"> const el = document.querySelector('smart-search') el.transformResponse = (json) => json.products.map((p) => ({ value: String(p.id), label: p.title, description: p.category, group: p.category, })) el.addEventListener('ss-menu-select', (e) => { console.log('selected:', e.detail.result) }) </script>
With Filters
Pass a filters JSON array to show toggleable filter chips above the results. Active filters
append field=value to the query string sent to your API.
<smart-search datasource="https://api.example.com/search?{{q}}" filters='[ {"field":"category","value":"smartphones", "label":"Smartphones"}, {"field":"category","value":"laptops", "label":"Laptops"} ]' ></smart-search> // Active filters compose the query: // ?q=phone&category=smartphones el.addEventListener('ss-filter-change', (e) => { console.log(e.detail.filters) // [{ field: 'category', value: 'smartphones' }] })
Dark Theme
Add theme="dark" for the built-in dark palette. theme="auto" (default) follows
prefers-color-scheme. All colors are overridable via CSS custom properties.
<!-- Built-in dark palette --> <smart-search theme="dark" datasource="..." ></smart-search> <!-- Follow system preference --> <smart-search theme="auto"></smart-search> /* Override via CSS custom properties */ smart-search { --ss-accent: #7c3aed; --ss-radius: 6px; --ss-input-height: 44px; }
Brand Themes
Override any CSS token per instance to match your brand. Set custom properties directly on the element — they cascade into the Shadow DOM automatically.
/* Violet — SaaS / Fintech */ #violet-search { --ss-accent: #7c3aed; --ss-accent-ring: rgba(124, 58, 237, 0.2); --ss-active: #ede9fe; } /* Emerald — Health / Eco */ #emerald-search { --ss-accent: #059669; --ss-accent-ring: rgba(5, 150, 105, 0.2); --ss-active: #d1fae5; } /* Rose — Fashion / E-commerce */ #rose-search { --ss-accent: #e11d48; --ss-accent-ring: rgba(225, 29, 72, 0.2); --ss-active: #ffe4e6; } /* Or set inline on the element: */ <smart-search style="--ss-accent:#7c3aed; --ss-active:#ede9fe" ></smart-search>
Custom Renderer
Use resultItemRenderer to return any DOM node as the result content. CSS tokens like
--ss-accent are available inside rendered nodes.
el.resultItemRenderer = (result) => { const { metadata } = result const card = document.createElement('div') card.style.cssText = 'display:flex;gap:12px;align-items:center' const img = document.createElement('img') img.src = metadata.thumbnail img.width = 44; img.height = 44 img.style.cssText = 'border-radius:6px;object-fit:cover' const info = document.createElement('div') info.innerHTML = ` <strong>${result.label}</strong> <div style="color:var(--ss-accent)"> $${metadata.price} </div>` card.append(img, info) return card }
Multi-select
Add the multiselect attribute to enable selecting multiple items. Selected items appear as
chips in the input. Listen to ss-multiselect-change or read
el.selectedItems directly.
<smart-search multiselect close-menu-on-select="false" datasource="..." ></smart-search> el.addEventListener( 'ss-multiselect-change', (e) => { // e.detail.items: SearchResult[] console.log(e.detail.items) } ) // Read state directly const selected = el.selectedItems
Static Options
Pre-load an options array for purely client-side filtering — no network requests. The
component filters by label and description as you type.
<smart-search
placeholder="Search languages..."
options='[
{
"value": "js",
"label": "JavaScript",
"description": "Web scripting",
"group": "Frontend"
},
{
"value": "go",
"label": "Go",
"description": "Systems language",
"group": "Backend"
}
]'
></smart-search>
// Or set programmatically:
el.options = myItems
Events Log
All interactions fire custom events on the element. Type, select, toggle a filter, or open the menu to see them stream in the log below.