Navigation
Expandable Search
Compact spring width morphing search input
detent-expandable-search
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 3
- Wave
- phase-3-forms
- Group
- Navigation
5.8 KB gzip for the class module · inlines the shared spring
Variants
Recorded states
expandedrecorded state; no setter
Usage
Import
import '/components/expandable-search/define.js';
// or register it yourself
import { DetentExpandableSearch } from '/components/expandable-search/expandable-search.js';
Attributes
default-valuedisabledexpandednameplaceholderrequiredvalue
Properties
valuedefaultValueplaceholderexpandeddisabledrequirednameonSearchexpandcollapse
Slots
No slots are recorded for this component.
Events
detent-search— { query: string }
Example
Runnable example: site/examples/expandable-search.ts. The snippet below is generated from the catalogued attributes.
<detent-expandable-search
default-value
disabled
expanded
name
placeholder="Search..."
required
value
></detent-expandable-search>
Property-only values
const element = document.querySelector('detent-expandable-search');
if (element !== null) {
// onSearch: (query: string) => void
element.onSearch = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/ExpandableSearch.tsxsha256 080bcd029e50…
Native files
The native module and its artifacts:
src/components/expandable-search/expandable-search.tssrc/components/expandable-search/styles.csssrc/components/expandable-search/define.tsdocs/components/expandable-search.mdsite/examples/expandable-search.tstests/browser/expandable-search.spec.tsevidence/components/expandable-search.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
default-value | — | — | — | Recorded in the catalog as an attribute. |
disabled | — | — | — | Recorded in the catalog as an attribute. |
expanded | — | — | — | Recorded in the catalog as an attribute. |
name | — | — | — | Recorded in the catalog as an attribute. |
placeholder | placeholder | string | 'Search...' | Kebab-case attribute; camelCase property. |
required | — | — | — | Recorded in the catalog as an attribute. |
value | — | — | — | Recorded in the catalog as an attribute. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
value | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
defaultValue | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
placeholder | string | 'Search...' | Property-only: assign from script; not accepted as an attribute. |
expanded | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
disabled | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
required | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
name | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
onSearch | (query: string) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
expand | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
collapse | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-search | onSearch | (query: string) => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The placeholder default stays the row's 'Search...' while the pinned source defaults to 'Search components, props...' (catalog wins; recorded).
- Clear keeps the field open (upstream's clear ran handleClose, collapsing mid-edit); collapse still clears and returns focus to the trigger.
- The trigger is a real `<button>` with aria-expanded/aria-controls instead of a clickable div with cursor-text, so the expanded state is announced.
- The ⌘K hint is decorative (aria-hidden) and hidden while expanded or while a query exists.
- Native additions: value, default-value, name, expanded, disabled, required, form association, reset/restore, plus expand()/collapse() which emit nothing.
- The width morph keeps springSnappy (380/30/0.5) on the shared helper, from 0 to --detent-expandable-search-width; a toggle mid-morph continues from the painted width at zero velocity.
- The palette is token-driven with color-mix instead of #0E0E0E/#141414/#FAFAFA dark-only literals.
What it does
A search field that expands from an icon into a full input on activation, then collapses again, with a dialog-style layout on mobile.
Upstream behaviour
- Spring physics width expansion
- Shortcut badge hint
- Instant clear button on input
Differences from upstream
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The placeholder default stays the row's 'Search...' while the pinned source defaults to 'Search components, props...' (catalog wins; recorded).
- Clear keeps the field open (upstream's clear ran handleClose, collapsing mid-edit); collapse still clears and returns focus to the trigger.
- The trigger is a real `<button>` with aria-expanded/aria-controls instead of a clickable div with cursor-text, so the expanded state is announced.
- The ⌘K hint is decorative (aria-hidden) and hidden while expanded or while a query exists.
- Native additions: value, default-value, name, expanded, disabled, required, form association, reset/restore, plus expand()/collapse() which emit nothing.
- The width morph keeps springSnappy (380/30/0.5) on the shared helper, from 0 to --detent-expandable-search-width; a toggle mid-morph continues from the painted width at zero velocity.
- The palette is token-driven with color-mix instead of #0E0E0E/#141414/#FAFAFA dark-only literals.