Detent web components
By Shane Logsdon

Navigation

Expandable Search

Implemented

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

  • expanded recorded 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-value
  • disabled
  • expanded
  • name
  • placeholder
  • required
  • value

Properties

  • value
  • defaultValue
  • placeholder
  • expanded
  • disabled
  • required
  • name
  • onSearch
  • expand
  • collapse

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.

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.tsx sha256 080bcd029e50…

Native files

The native module and its artifacts:

  • src/components/expandable-search/expandable-search.ts
  • src/components/expandable-search/styles.css
  • src/components/expandable-search/define.ts
  • docs/components/expandable-search.md
  • site/examples/expandable-search.ts
  • tests/browser/expandable-search.spec.ts
  • evidence/components/expandable-search.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
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.
placeholderplaceholderstring'Search...'Kebab-case attribute; camelCase property.
required———Recorded in the catalog as an attribute.
value———Recorded in the catalog as an attribute.

Properties

Properties
PropertyTypeDefaultNotes
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.
placeholderstring'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) => voidundefinedProperty-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

Events
EventUpstream propPayload typeNotes
detent-searchonSearch(query: string) => voidComposed, 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.
Previous: Expandable Data Row Next: FAQ

Docs

Components

Project