Skip to content

feat(react-search): add SearchBox typeahead/autocomplete Storybook story and design spec#35875

Open
Copilot wants to merge 4 commits intomasterfrom
copilot/add-searchbox-typeahead-feature
Open

feat(react-search): add SearchBox typeahead/autocomplete Storybook story and design spec#35875
Copilot wants to merge 4 commits intomasterfrom
copilot/add-searchbox-typeahead-feature

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

The SearchBox component lacked any typeahead (autocomplete) guidance or implementation, leaving users without a clear path to building search-with-results patterns recommended by the Fluent 2 design docs.

Changes

New: TYPEAHEAD-SEARCHBOX-SPEC.md

Added the design spec (referenced in the issue) documenting the proposed API surface, component states, interaction model, and accessibility requirements for a typeahead SearchBox pattern.

New: SearchBoxTypeahead.stories.tsx

Complete Storybook story demonstrating the composable typeahead pattern using existing primitives:

// Compose SearchBox with a results listbox — no sealed wrapper needed
<div style={{ position: 'relative' }}>
  <SearchBox
    role="combobox"
    aria-autocomplete="list"
    aria-controls={listboxId}
    aria-expanded={showDropdown}
    aria-activedescendant={activedescendant}
    value={query}
    onChange={handleChange}
    onKeyDown={handleKeyDown}
    root={{ onBlur: handleBlur }}
  />
  <ul id={listboxId} role="listbox">
    {isLoading ? <Spinner size="tiny" label="Loading results…" /> : results.map(...)}
  </ul>
</div>

Covers:

  • Async search with cancellable in-flight requests (no race conditions)
  • Loading state via Spinner inside the dropdown
  • Keyboard navigationArrowDown/ArrowUp, Enter to select, Escape to dismiss
  • Full ARIA wiringrole="combobox", aria-activedescendant, aria-live region for result count announcements
  • Griffel-only stylingvisuallyHidden class instead of inline styles

Updated: SearchBoxBestPractices.md + index.stories.tsx

Added a best-practice recommendation pointing to the typeahead story, and exported the new story from the component's story index.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature]: SearchBox Typeahead to Match Design Docs</issue_title>
<issue_description>### Area

React Components (@fluentui/react-components)

Describe the feature that you would like added

The FluentUI 2 design docs on Searchbox suggests that the there is an expected design pattern of showing some initial results while typing. There doesn't seem to be something built into the React component for SearchBox but this seems like an opportunity area. If nothing else, maybe something in the docs to suggest "Build your own" if there are not plans to implement something for typeahead results.

Additional context

There is sort of a work-around by using a Combobox, but this feels less practical when searching against an API that has an arbitrarily large number of possible results. There's the Fluent UI Blazor "Autocomplete" but that's obvious not a react implementation, and feels very similar to the Combobox solution.

Have you discussed this feature with our team

No response

Validations

  • Check that there isn't already an issue that requests the same feature to avoid creating a duplicate.

Priority

Medium</issue_description>

<agent_instructions>Use this spec for details: https://github.com/microsoft/fluentui/blob/8cf238bda5eab1d884fa2b935a79d91c329bcf89/packages/react-components/react-search/library/docs/TYPEAHEAD-SEARCHBOX-SPEC.md</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@gouttierre 📢 - This has been brought up with Fluent Design Team. - Conversations are underway to determine the next steps.

~cc @ValentinaKozlova , @dmytrokirpa </comment_new>
<comment_new>@gouttierre
📢

  • Conversations are underway with next steps. i.e., (create a wrapper component with refined usage guidance)

~cc @mindlessroman, @smhigley </comment_new>
<comment_new>@ValentinaKozlova
keep open</comment_new>
<comment_new>@ValentinaKozlova
More info about this feature: https://github.com/microsoft/fluentui/blob/8cf238bda5eab1d884fa2b935a79d91c329bcf89/packages/react-components/react-search/library/docs/TYPEAHEAD-SEARCHBOX-SPEC.md</comment_new>


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

…HBOX-SPEC.md

Co-authored-by: ValentinaKozlova <11574680+ValentinaKozlova@users.noreply.github.com>
Copilot AI changed the title [WIP] [Feature]: Add typeahead functionality to SearchBox feat(react-search): add SearchBox typeahead/autocomplete Storybook story and design spec Mar 17, 2026
Copilot AI requested a review from ValentinaKozlova March 17, 2026 11:00
@github-actions
Copy link

github-actions bot commented Mar 17, 2026

📊 Bundle size report

✅ No changes found

@github-actions
Copy link

Pull request demo site: URL

@ValentinaKozlova ValentinaKozlova marked this pull request as ready for review March 18, 2026 08:05
@ValentinaKozlova ValentinaKozlova requested a review from a team as a code owner March 18, 2026 08:05
@dmytrokirpa dmytrokirpa requested a review from mainframev March 18, 2026 13:03
Copy link
Contributor

@smhigley smhigley left a comment

Choose a reason for hiding this comment

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

Thanks so much for making this PR! Overall the semantics look good, just a few notes around handling specific screen reader behaviors (screen readers are weird and especially so with comboboxes 😅)

/>

{/* Live region announces result count for screen readers */}
<div aria-live="polite" aria-atomic="true" className={styles.visuallyHidden}>
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to use the useTypingAnnounce utility -- it handles things like rapid/overlapping changes (when an id is passed), clears out the text after it's announced so it isn't reachable by screen reader users inline as it would be here, and also uses document.ariaNotify in browsers that support it.

The reason to use useTypingAnnounce over useAnnounce is because it handles the reason why live regions that fire while the user is typing are problematic -- it prevents the live region from firing until the user pauses text input so it doesn't interfere with keyboard echo.

(I love the inclusion of the live region to let screen reader users know about the suggestions 😊)

} else if (e.key === 'Escape') {
setIsOpen(false);
setFocusedIndex(-1);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

A couple additions that are related to the way screen readers handle "focus" (not keyboard focus, but the screen reader cursor) and aria-activedescendant -- when aria-activedescendant is set or changed, SR focus gets pulled out of the input and to the active option. That's generally good, but also can interfere with interacting with the text in the input. Typing will automatically pull SR focus back to the input without our interference, but arrowing back and forth to move the text insertion cursor will not.

So, the fix is to also listen to ArrowLeft and ArrowRight, and clear the value for activedescendant when those are used. (we also do this in Combobox, in useInputTriggerSlot)

This probably needs to be handled in a separate state from focusedIndex, since if the user were to start up/down arrowing again, they should start again from the same place they were previously.

// Close if focus leaves both the input and the listbox
const relatedTarget = e.relatedTarget as Node | null;
const listboxEl = document.getElementById(listboxId);
if (!listboxEl?.contains(relatedTarget)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

it should also check if the clear button is focused and not dismiss in that case either. Right now, since it dismisses when clear is focused, VoiceOver on macOS & iOS and Android Talkback can't access the list of suggestions.

aria-controls={listboxId}
aria-expanded={showDropdown || noResults}
aria-activedescendant={activedescendant}
role="combobox"
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually don't want role=combobox here for a few reasons:

  • it overrides the semantics from type=search, which are more helpful in describing the component's intended purpose in this case
  • screen reader users tend to go looking for text inputs / "edit boxes" when looking for search functionality, and the combobox role will prevent the input from being accessed that way
  • search inputs can usually be used without selecting an item (i.e. just searching custom typed text), and the combobox role implies that isn't possible
  • the activedescendant functionality will still work fine without the combobox role, and the live region does a really good job at letting the user know there are suggestions available even without the role

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: SearchBox Typeahead to Match Design Docs

3 participants