You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds tokens mode to Autosuggest. When a tokens array is provided (including empty), accepted values display as inline dismissible token pills before the text input, with overflow into a +N pill that opens a focus-trapped portal dropdown.
New props:
tokens: ReadonlyArray<AutosuggestProps.Token> — activates tokens mode when provided (controlled)
i18nStrings.enteredTextLabel: (value: string) => string — replaces top-level enteredTextLabel; return Add "${value}" or Use: "${value}" based on your state
i18nStrings.tokenOverflowAriaLabel: (count: number) => string — accessible label for the +N overflow pill
Behaviour:
Selecting an item (Enter or dropdown click) adds it as a token
Tokens overflow into a +N pill; clicking opens a dropdown
Clear button (×) appears when input has typed text
Accessibility:
Keyboard: ArrowLeft/Right navigate between tokens and input; Backspace on empty input focuses last token; Backspace/Delete on a focused token dismisses it; focus returns to input after last token dismissed
Backspace focus uses imperative focusTokenAtIndex so it fires even when focusedTokenIndex hasn't changed (avoids React setState no-op)
Unit tests (autosuggest-input-tokens.test.tsx) cover token rendering, add/dismiss, keyboard nav, overflow pill, ARIA, i18n resolution, and Backspace idempotency. Integration tests (autosuggest-tokens.test.ts) cover full add-token flows, overflow pill open/close/Escape, keyboard nav, and clear button.To review locally: run npm run start and open http://localhost:8080/autosuggest/tokens-mode. The interactive demo at the top lets you add/dismiss tokens and trigger overflow. Static scenario rows below cover all states.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
❌ Patch coverage is 97.58713% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.71%. Comparing base (fdcc7a2) to head (a311d2f). ⚠️ Report is 2 commits behind head on main.
The Arabic autosuggest catalog was not given i18nStrings.enteredTextLabel, so token mode falls through to its legacy enteredTextLabel translation (“Use”) and labels the add-token action incorrectly. Add the missing Arabic token-mode message and avoid using the legacy key when isTokenMode is true.
Add Arabic overflow label translation
src/autosuggest/internal.tsx:104
The Arabic catalog also lacks this new overflow key, so Arabic users receive the hardcoded English “N more items” label. Add the Arabic catalog entry and remove the English fallback in accordance with the repository i18n convention.
Add autosuggest translation key to all locale catalogs
src/autosuggest/internal.tsx:109
Only the English autosuggest catalog defines this new key; the similarly named localized entries belong to prompt-input, a different component namespace. For every non-English locale this lookup returns undefined and the hardcoded English fallback is announced, violating the repository i18n rule. Add the autosuggest key to all locale catalogs and let the provider supply the default instead of embedding English here.
Track icon identity in overflow measurement dependencies
String interpolation does not track icon changes: React elements stringify to the same [object Object]. Replacing a token icon with a differently sized icon while preserving labels/count therefore leaves overflow measurements stale. Pass an identity-bearing dependency (such as the token array) to the measurement hook instead of serializing React nodes.
Reset overflow state when all tokens become visible
When a resize or controlled token update makes every token visible, the overflow panel unmounts but overflowOpen remains true. handleFocus then continues suppressing the suggestions dropdown even though no overflow UI exists. Reset overflowOpen whenever hiddenTokens becomes empty.
Hardcoded English fallbacks break Autosuggest localization
src/autosuggest/internal.tsx:99
Cloudscape i18n convention 1000000 prohibits hardcoded English fallbacks. These fallbacks also mask incomplete catalogs: Arabic and Thai omit all three new Autosuggest keys, and every non-English Autosuggest catalog omits tokenInsertedAriaLabel, so those locales announce English text. Add every key to every locale and rely on useInternalI18n rather than these literals.
String interpolation does not distinguish React icon elements: different <Icon>/SVG nodes all stringify to [object Object]. Replacing a token icon with a differently sized icon while keeping the same labels/count therefore does not rerun measurement, leaving stale overflow layout. Depend on the token array/icon identity or observe the measurement elements instead.
This issue also appears on line 199 of the same file.
Overriding invalid to false removes aria-invalid from the actual combobox; the outer group only receives invalid styling and has no equivalent ARIA state. Consequently, token-mode validation errors are not communicated to assistive technology. Suppress only the input's visual invalid treatment while preserving aria-invalid on the combobox.
The first visible token is charged an extra gap even though budgetWithPill already reserves the gap between the pill and tokens. For example, a 48px token is rejected from a 50px token budget when the gap is 4px, so the component hides a token that actually fits.
Generated class substring used as integration selector
Cloudscape SCSS/test-utils convention 1000003 forbids integration selectors based on generated class substrings. [class*="overflow-panel"] can match unrelated elements or break when styles are renamed; expose the panel through a test class and a static test-utils selector instead.
Documentation incorrectly limits enteredTextLabel to token mode
src/autosuggest/interfaces.ts:194
This says the whole object is token-mode-only, but i18nStrings.enteredTextLabel is intentionally resolved and tested in default mode as the replacement for the deprecated top-level prop. The public documentation would incorrectly tell default-mode consumers not to use the replacement.
The reason will be displayed to describe this comment to others. Learn more.
A 3.3k lines of code in a single test file is too much: the tests can serve as code documentation when written well, but they should be discoverable. I recommend splitting these tests into multiple files - grouped by features that we test (e.g. tokens, tokens overflow, tokens keyboard nav., etc.), move the shared code to some common.tsx helper, and try to reduce the number of tests by avoiding duplication, unnecessary assertions, etc.
The reason will be displayed to describe this comment to others. Learn more.
Here is what my review agent says on this file:
The file is large because it was written to hit coverage lines rather than to check behaviour.
It was written in coverage passes. 67 test or describe titles cite source line numbers ("(lines 591, 595)"), and blocks are labelled "fourth-pass" and "FIFTH-PASS". The FIFTH-PASS block alone is about 670 lines. The line numbers are already stale: the code those tests target is now at lines 374–381.
Many tests check nothing. 64 of the 188 tests only assert that an element exists, and 14 create a jest.fn() that is never asserted. "mousedown outside the component closes the dropdown" checks that the combobox still exists.
Some tests pass without running their assertion. "overflow pill button has tabIndex=-1" wraps its expect in if (pill), and in practice pill is null, so nothing is checked. The source sets the pill to tabIndex={0}, so the assertion would fail if it ran. Four tests use expect(true).toBe(true) as a fallback.
The layout mocks are copied over and over. There are 10 overflow render helpers, and 6 of them are identical (token 120px, pill 40px, container 400px). Across the file there are 22 HTMLElement.prototype.offsetWidth overrides and 27 getComputedStyle mocks. One override, at line 3016, is never restored, so it leaks into every later test in the file.
It reaches into the DOM directly. It uses 206 querySelector calls, 68 hashed-class substring selectors ([class*="overflow-panel"]), and hand-built dispatchEvent(new KeyboardEvent…) calls. The PR already adds findInlineToken, findOverflowPill and findTokenTrigger to the test utils.
My rough estimate is 120–130 tests in about 900–1,100 lines, with coverage at or above today's. I haven't written the refactor, so treat the size as an estimate. Also, if the pill tabIndex test is fixed so it actually renders the overflow state, it will fail. The PR then has to decide whether the pill should be a tab stop: the source sets tabIndex={0}, while the test expects -1.
The reason will be displayed to describe this comment to others. Learn more.
Autosuggest input is an internal component reused between autosuggest and property filter. The tokens feature is needed for autosuggest, but not for property filter - so why are we adding it here and not inside autosuggest? Can autosuggest input expose a slot for token and some props required to make responsiveness work?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds tokens mode to Autosuggest. When a
tokensarray is provided (including empty), accepted values display as inline dismissible token pills before the text input, with overflow into a+Npill that opens a focus-trapped portal dropdown.New props:
tokens: ReadonlyArray<AutosuggestProps.Token>— activates tokens mode when provided (controlled)i18nStrings.enteredTextLabel: (value: string) => string— replaces top-levelenteredTextLabel; returnAdd "${value}"orUse: "${value}"based on your statei18nStrings.tokenOverflowAriaLabel: (count: number) => string— accessible label for the+Noverflow pillBehaviour:
+Npill; clicking opens a dropdownAccessibility:
focusTokenAtIndexso it fires even whenfocusedTokenIndexhasn't changed (avoids React setState no-op)Kick off Doc: https://chorus.aws.dev/doc/Op6bEowqHzMY/Kick-offScope-alignment-and-Design-SO-input-flexibility
API Proposal Doc: https://chorus.aws.dev/doc/qJ3Ttxk8R7CZ/API-Proposal-Autosuggest--Inline-Tokens-Mode
How has this been tested?
Unit tests (
autosuggest-input-tokens.test.tsx) cover token rendering, add/dismiss, keyboard nav, overflow pill, ARIA, i18n resolution, and Backspace idempotency. Integration tests (autosuggest-tokens.test.ts) cover full add-token flows, overflow pill open/close/Escape, keyboard nav, and clear button.To review locally: runnpm run startand openhttp://localhost:8080/autosuggest/tokens-mode. The interactive demo at the top lets you add/dismiss tokens and trigger overflow. Static scenario rows below cover all states.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.