Skip to content

feat(selector): built-in search magnifier + clear button in dropdown search - #4636

Merged
cixzhang merged 4 commits into
mainfrom
feat/selector-search-affordances
Aug 4, 2026
Merged

feat(selector): built-in search magnifier + clear button in dropdown search#4636
cixzhang merged 4 commits into
mainfrom
feat/selector-search-affordances

Conversation

@freddymeta

@freddymeta freddymeta commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What

The searchable dropdown (Selector & MultiSelector) now renders its dropdown search field as a TextInput rather than a bespoke control. That gives it two standard search affordances, both inside the field, with no new props or config knob:

  • Search magnifier — TextInput's startIcon, rendered inside the field's leading edge whenever hasSearch is on. Decorative (aria-hidden), outside the combobox contract.
  • Clear (✕) button — TextInput's built-in hasClear, rendered inside the trailing edge once a query is typed. Clicking it resets the query and returns focus to the input.

The search field now shares TextInput's border, focus ring, and sizing, so it looks and behaves like every other input in the system instead of being a one-off.

How

  • renderSearch() now returns a <TextInput isLabelHidden startIcon="search" hasClear width="100%" …> instead of a hand-rolled [icon] [input] [clear] flex row. width="100%" makes the field flush to the dropdown edges (the wrapper keeps only the dropdown's inline/block padding).
  • A11y / combobox contract is untouched. The underlying <input> remains the sole combobox: role="combobox", aria-expanded, aria-controls, aria-autocomplete, and aria-activedescendant pass through to it via BaseProps, and arrow/Enter/Escape/PageUp/PageDown navigation is unchanged. The magnifier is decorative; the clear button is TextInput-internal — neither is part of the combobox contract.
  • Clear button is keyboard-reachable. Previously forward-Tab from the search input dismissed the popup, so the clear ✕ (a later tab stop inside the popup) was unreachable by keyboard. Now, when a query is showing the clear button, forward-Tab moves focus to it and keeps the popup open; tabbing off the button (or Tab with no query) dismisses as before. Shift+Tab returns to the input natively.

Theming

No new theme targets. The search field is a TextInput, so it is themeable through the standard text-input target (size/status aware); the magnifier and clear glyph are Icons and inherit Icon theming. This removes the previously-proposed *-search-icon / *-search-clear-icon targets in favor of composition.

Removed

The bespoke <input> + magnifier + clear-button markup, the searchIcon / searchInput / searchClearButton StyleX blocks, the handleSearchClear handler, the *-search-icon / *-search-clear-icon theme targets, and the now-unused clearSearch i18n keys.

Non-breaking, but note the visual default

No API change. The clear button only appears with a typed query. The magnifier defaults on, so existing hasSearch dropdowns gain a leading glyph inside the field — an intended visual default, flagged in the changeset. The clear button's accessible name is now derived from the field label ("Clear Search options").

Testing

  • Magnifier renders inside the field when hasSearch and is aria-hidden; clear appears on a query, resets + refocuses on click, and is absent when empty; the combobox contract stays on the input.
  • New keyboard tests: forward-Tab from the input reaches the clear button (popup stays open) when a query is present; Tab with no query dismisses.
  • Selector + MultiSelector suites (161 tests) and the themingTargets suite (275 tests) pass; typecheck and eslint on the changed files are clean.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 1, 2026
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 3, 2026 3:35am

Request Review

@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review labels Aug 1, 2026
…search

The searchable dropdown (Selector & MultiSelector) now has two built-in search
affordances rather than opt-in props:

- A leading magnifier icon, rendered whenever `hasSearch` is on. It is
  decorative (aria-hidden) and sits outside the combobox contract.
- A trailing clear (✕) button, rendered once a query is typed. Clicking it
  resets the query and returns focus to the input. It is a sibling of the
  input, not part of the combobox — the input remains the combobox and keeps
  its role/aria/keydown navigation.

Both are on by default (standard search-field affordances) with no config knob.
Themeable via selector-search-icon / selector-search-clear-icon and the
multi-selector equivalents. Non-breaking, but note the magnifier is a new
default glyph on existing hasSearch usages.
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

MultiSelector (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1337 -
Complexity N/A Very High (156) -
Selector (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1320 -
Complexity N/A Very High (117) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.9KB 1.3KB

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Aug 1, 2026
…asClear)

The dropdown search field was a bespoke flex row — a raw <input role=combobox>
with a magnifier Icon and a clear <button> as siblings, plus ~55 lines of
duplicated input styling and two new theme targets. Replace it with a TextInput:
the magnifier is its startIcon (now inside the field) and the clear (X) is its
built-in hasClear (reset + refocus). role and aria-* pass through to the
underlying <input> via BaseProps, so the combobox contract is unchanged.

Removes the bespoke input/magnifier/clear markup, the searchIcon/searchInput/
searchClearButton styles, handleSearchClear, the *-search-icon / *-search-clear-icon
theme targets, and the now-unused clearSearch i18n keys. The search field now
matches every other Astryx input (border, focus ring, sizing).
- width=100% so the search TextInput fills the dropdown (was sized to content,
  leaving a gap at the end).
- Forward-Tab from the search input no longer dismisses the popup when a query
  is showing the clear (X) button; instead focus moves to that button so it is
  keyboard-reachable. Tabbing off the button (or Tab with no query) dismisses
  as before. Shift+Tab returns to the input natively.
… tests

Apply the same width=100% flush and Tab-to-clear-button behavior to
MultiSelector's dropdown search, and cover the new keyboard behavior in both
Selector and MultiSelector suites (Tab moves to the clear button when a query
is present; Tab with no query dismisses).
@cixzhang
cixzhang enabled auto-merge (squash) August 4, 2026 02:29
@cixzhang
cixzhang merged commit 13bda9d into main Aug 4, 2026
20 of 21 checks passed
@github-actions
github-actions Bot deleted the feat/selector-search-affordances branch August 4, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants