Skip to content

[EuiSearchBar] Surface change source on onChange so consumers can distinguish typing from custom-filter changes #9647

@clintandrewhall

Description

@clintandrewhall

Problem

EuiSearchBar.onChange is invoked from two internal entry points — onSearch (free-text typing) and onFiltersChange (a custom_component filter calling its provided onChange) — but both funnel through notifyControllingParent, which only forwards { query, queryText, error } to the consumer. The consumer cannot tell which path produced the change.

Use case

In @kbn/content-list-toolbar, Content List drives URL persistence via history.push vs history.replace:

  • Typing keystrokes → history.replace (don't create one history entry per character).
  • Committed filter actions → history.push (Back/Forward should move between filter states).

Because EUI doesn't expose the source, the toolbar currently has to wrap each custom_component filter in a tiny HOC that intercepts onChange before EUI sees it, dispatches with source: 'filter', and bypasses EUI's controlled-state notification entirely. A WeakMap<Component, WrappedComponent> cache is needed because CustomComponentFilter renders config.component directly, so a fresh wrapper per recompute would unmount/remount each filter's internals (popover state, debounce timers, in-flight facet queries).

Proposal

Plumb a source discriminator through notifyControllingParent into the consumer's onChange:

onChange?: (args: {
  query: Query | null;
  queryText: string;
  error: Error | null;
  source: 'search' | 'filters'; // new
}) => void;

Alternatively, expose a separate onFiltersChange prop so the typing path and filter path stay distinct from the top.

Either change would let @kbn/content-list-toolbar (and any other consumer that cares about intent) drop the per-component wrapper and the WeakMap cache, collapsing use_filters.ts to a single handleSearchChange that branches on args.source.

Workaround in tree

See wrapperCache / getWrappedFilterComponent / wrapCustomFilters in use_filters.ts, and the originating discussion at elastic/kibana#267632 (comment).

Metadata

Metadata

Assignees

No one assigned

    Labels

    kibanarequestClear use case, business priority. Requires a clear yes/no answer or coordination.tech debt
    No fields configured for Enhancement.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions