Skip to content

feat(core-ui): Add searchMatcher prop to CompactSelect#108714

Merged
JonasBa merged 3 commits intomasterfrom
jb/compactselect/search-fn
Feb 23, 2026
Merged

feat(core-ui): Add searchMatcher prop to CompactSelect#108714
JonasBa merged 3 commits intomasterfrom
jb/compactselect/search-fn

Conversation

@JonasBa
Copy link
Member

@JonasBa JonasBa commented Feb 20, 2026

Add a searchMatcher prop to CompactSelect (and CompositeSelect) that lets callers replace the built-in search filtering with a matcher. This will enable us to provide better searching capabilities like fuzzy searching

Allow callers to provide a custom match function via the new
searchMatcher prop. When provided, it replaces the built-in
case-insensitive substring matching so callers can implement
arbitrary logic (e.g. suffix matching, fuzzy search, matching on
non-label fields).

The function receives the full option object and the current search
string, returning true when the option should be visible.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Feb 20, 2026
@JonasBa JonasBa marked this pull request as ready for review February 20, 2026 19:19
@JonasBa JonasBa requested a review from a team as a code owner February 20, 2026 19:19
Add tests verifying that:
- clearing the search input restores the full option list
- closing and reopening the menu resets the search query and shows all options

Both ListBox and GridList variants are covered.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Member

@natemoo-re natemoo-re left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition!

Comment on lines +180 to +186
/**
* Custom function to determine whether an option matches the search query (applicable
* only when `searchable` is true). Receives the option and the current search string,
* and should return true if the option matches. If not provided, defaults to
* case-insensitive substring matching on `textValue` or `label`.
*/
searchMatcher?: (option: SelectOptionWithKey<SelectKey>, search: string) => boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding new props that require searchable (like <CompactSelect searchable searchMatcher={fn} searchPlaceholder={t("Search...")} />), did you consider an object form to handle search-related configuration?

search: false | { matcher: fn, placeholder: t('Search...') }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I punted consolidation for a different time, but yeah, all of these are becoming weird. Ideally, we could just expose the input component and have it do the internal state calls. I'll try think of this a bit with the subsequent work on these filter components, I'm starting to see some more patterns emerge

@JonasBa JonasBa merged commit 78dd026 into master Feb 23, 2026
63 checks passed
@JonasBa JonasBa deleted the jb/compactselect/search-fn branch February 23, 2026 20:58
JonasBa added a commit that referenced this pull request Feb 23, 2026
…ing (#108719)

Stacked on #108714.

Extends the `searchMatcher` prop introduced in the base PR so it can
optionally return a `SearchMatchResult` object in addition to a plain
`boolean`.

```ts
interface SearchMatchResult {
  score: number;
}
```

When a matcher returns `SearchMatchResult`, the option is shown and its
`score` is used to sort matching options — higher scores appear first.
Returning `false` still hides the option. Returning `true` (the existing
behaviour) shows it with no ordering influence, so the change is fully
additive.

---

**Update**: `searchMatcher` now always returns `SearchMatchResult` — the
`boolean` return path is removed. A score > 0 means the option matches;
score <= 0 hides it. The default implementation returns `{score: 1}` for
a substring match and `{score: 0}` otherwise. Sorting is only triggered
when a custom `searchMatcher` is provided, so the default path pays no
extra cost.

Sorting is scoped: within each section for sectioned lists, and globally
for flat lists. Options with equal scores maintain their original
relative order (stable sort).

The `SearchMatchResult` type and the new `getSortedItems` utility are
exported from the package for callers building custom composite selects.

---------

Co-authored-by: Claude <noreply@anthropic.com>
mchen-sentry pushed a commit that referenced this pull request Feb 24, 2026
Add a `searchMatcher` prop to `CompactSelect` (and `CompositeSelect`)
that lets callers replace the built-in search filtering with a matcher.
This will enable us to provide better searching capabilities like fuzzy
searching

---------

Co-authored-by: Claude <noreply@anthropic.com>
mchen-sentry pushed a commit that referenced this pull request Feb 24, 2026
…ing (#108719)

Stacked on #108714.

Extends the `searchMatcher` prop introduced in the base PR so it can
optionally return a `SearchMatchResult` object in addition to a plain
`boolean`.

```ts
interface SearchMatchResult {
  score: number;
}
```

When a matcher returns `SearchMatchResult`, the option is shown and its
`score` is used to sort matching options — higher scores appear first.
Returning `false` still hides the option. Returning `true` (the existing
behaviour) shows it with no ordering influence, so the change is fully
additive.

---

**Update**: `searchMatcher` now always returns `SearchMatchResult` — the
`boolean` return path is removed. A score > 0 means the option matches;
score <= 0 hides it. The default implementation returns `{score: 1}` for
a substring match and `{score: 0}` otherwise. Sorting is only triggered
when a custom `searchMatcher` is provided, so the default path pays no
extra cost.

Sorting is scoped: within each section for sectioned lists, and globally
for flat lists. Options with equal scores maintain their original
relative order (stable sort).

The `SearchMatchResult` type and the new `getSortedItems` utility are
exported from the package for callers building custom composite selects.

---------

Co-authored-by: Claude <noreply@anthropic.com>
wedamija pushed a commit that referenced this pull request Feb 24, 2026
Add a `searchMatcher` prop to `CompactSelect` (and `CompositeSelect`)
that lets callers replace the built-in search filtering with a matcher.
This will enable us to provide better searching capabilities like fuzzy
searching

---------

Co-authored-by: Claude <noreply@anthropic.com>
wedamija pushed a commit that referenced this pull request Feb 24, 2026
…ing (#108719)

Stacked on #108714.

Extends the `searchMatcher` prop introduced in the base PR so it can
optionally return a `SearchMatchResult` object in addition to a plain
`boolean`.

```ts
interface SearchMatchResult {
  score: number;
}
```

When a matcher returns `SearchMatchResult`, the option is shown and its
`score` is used to sort matching options — higher scores appear first.
Returning `false` still hides the option. Returning `true` (the existing
behaviour) shows it with no ordering influence, so the change is fully
additive.

---

**Update**: `searchMatcher` now always returns `SearchMatchResult` — the
`boolean` return path is removed. A score > 0 means the option matches;
score <= 0 hides it. The default implementation returns `{score: 1}` for
a substring match and `{score: 0}` otherwise. Sorting is only triggered
when a custom `searchMatcher` is provided, so the default path pays no
extra cost.

Sorting is scoped: within each section for sectioned lists, and globally
for flat lists. Options with equal scores maintain their original
relative order (stable sort).

The `SearchMatchResult` type and the new `getSortedItems` utility are
exported from the package for callers building custom composite selects.

---------

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions bot locked and limited conversation to collaborators Mar 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants