A form-associated custom element providing search-box UX: inline search icon, clear button, and Enter-to-search event. Integrates with x-form via ElementInternals.
<x-search-field name="q" placeholder="Search…" label="Site search"></x-search-field>
| Attribute | Type | Default | Notes |
|---|---|---|---|
name | string | "" | Field name in form payload |
value | string | "" | Current value (reflects input) |
placeholder | string | "" | Input placeholder text |
label | string | "" | Sets aria-label on the input |
disabled | boolean | absent | Disables input, hides clear button |
required | boolean | absent | Marks field as required |
autocomplete | enum | "off" | "on" | "off" |
debounce | number | 0 | Milliseconds to debounce x-search-field-input; 0/absent/invalid = fire immediately |
All properties reflect to their corresponding attributes.
| Property | Type |
|---|---|
value | string |
name | string |
placeholder | string |
label | string |
autocomplete | string |
disabled | boolean |
required | boolean |
debounce | number |
Reading value returns the live input.value (not the attribute). Setting value syncs both the attribute and the input DOM node.
| Event | Bubbles | Composed | Cancelable | Detail |
|---|---|---|---|---|
x-search-field-input | yes | yes | no | {name, value} |
x-search-field-change | yes | yes | no | {name, value} |
x-search-field-search | yes | yes | yes | {name, value} |
x-search-field-clear | yes | yes | no | {name} |
x-search-field-search is dispatched when the user presses Enter. It is cancelable but does not auto-submit a parent form.
Set the debounce attribute (or .debounce property) to a positive millisecond count to coalesce rapid typing into a single x-search-field-input event, fired once the user pauses. This is opt-in — with debounce absent or 0, the event fires on every keystroke as before.
Only the outward x-search-field-input event is delayed. Local UI feedback (the clear button, form value, and validity) stays synchronous with each keystroke, so the field never feels laggy. The coalesced event carries the field's final value. A pending debounced dispatch is cancelled when the field is cleared, the parent form is reset, or the element is disconnected — so a stale event never lands after the value is gone.
x-search-field-change (blur), x-search-field-search (Enter), and x-search-field-clear are never debounced.
<!-- Fire x-search-field-input at most once per 300ms of quiet typing -->
<x-search-field name="q" placeholder="Search…" debounce="300"></x-search-field>
:host
style
div[part=wrapper]
span[part=icon] — inline SVG magnifying glass, pointer-events:none
input[part=input] — type="search", native clear button suppressed
button[part=clear] — "×", hidden (.clear-hidden) when empty or disabled
| Property | Default (light) |
|---|---|
--x-search-field-bg | #ffffff |
--x-search-field-color | #111827 |
--x-search-field-border | 1px solid #d1d5db |
--x-search-field-border-radius | 6px |
--x-search-field-focus-ring-color | #2563eb |
--x-search-field-icon-color | #9ca3af |
--x-search-field-clear-color | #9ca3af |
--x-search-field-disabled-opacity | 0.45 |
Dark mode values are applied automatically via @media (prefers-color-scheme: dark) inside the shadow style.
x-search-field is a form-associated custom element (static formAssociated = true). It:
<form> submission via ElementInternals.setFormValuerequired validation (valueMissing) via ElementInternals.setValidityreportValidity() through the browser's ElementInternals implementationformDisabledCallback (syncs disabled state)formResetCallback (clears value)<x-form>
<x-search-field name="q" label="Site search" placeholder="Search…" required></x-search-field>
<button type="submit">Search</button>
<button type="reset">Clear</button>
</x-form>
x-form's collect-values picks up x-search-field via the (.-value field) property fallback — no x-form changes required.
label attribute sets aria-label on the inner <input> (no visible label element is rendered).aria-required is set to "true" / "false" on the input based on the required attribute.aria-label="Clear search".aria-hidden="true" and is excluded from pointer events.@media (prefers-reduced-motion: reduce).<x-search-field id="site-search" name="q" label="Search" placeholder="Search…"></x-search-field>
<script>
const sf = document.getElementById('site-search');
sf.addEventListener('x-search-field-search', e => {
console.log('Search:', e.detail.value);
});
sf.addEventListener('x-search-field-clear', () => {
console.log('Cleared');
});
</script>
<x-form id="search-form">
<x-search-field name="q" label="Site search" placeholder="Search the site…" required></x-search-field>
<button type="submit">Search</button>
<button type="reset">Reset</button>
</x-form>
<script>
document.getElementById('search-form').addEventListener('x-form-submit', e => {
console.log('Form values:', e.detail.values); // { q: "…" }
});
</script>
x-search-field {
--x-search-field-bg: #f1f5f9;
--x-search-field-border-radius: 9999px;
--x-search-field-focus-ring-color: #7c3aed;
}
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |