Skip to content

fix(InputMenu/SelectMenu): re-highlight first item when items change#6538

Merged
benjamincanac merged 1 commit into
v4from
fix/input-select-menu-create-highlight
Jun 3, 2026
Merged

fix(InputMenu/SelectMenu): re-highlight first item when items change#6538
benjamincanac merged 1 commit into
v4from
fix/input-select-menu-create-highlight

Conversation

@benjamincanac
Copy link
Copy Markdown
Member

@benjamincanac benjamincanac commented Jun 2, 2026

🔗 Linked issue

Resolves #5974

❓ Type of change

  • 🐞 Bug fix (a non-breaking change that fixes an issue)

📚 Description

reka-ui only re-highlights the first item when its collection goes from empty to non-empty (ComboboxInput's filterState watch guards on oldValue.count === 0). With create-item, the create item is always registered, so the count never drops to 0 and the highlight stays stale when async items load.

This caused the issues reported in #5974:

  • After async items load, the stale "Create" item stays highlighted, so pressing Enter creates instead of selecting the first option.
  • When focus ends up outside the combobox (e.g. items disappear), Enter falls through to TagsInput's internal add, producing a phantom tag and inconsistent onCreate.

Fix: re-highlight the first item via reka-ui's exposed highlightFirstItem() whenever items change while the menu is open. We wait one extra tick first, since freshly mounted items only register in reka-ui's collection after their element ref is set (otherwise the empty→populated transition re-highlights the stale create item).

No custom Enter handler is needed: once the correct item is highlighted, reka-ui's native Enter handling selects/creates it.

Added regression tests for both components covering the async-items + create-item flow.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

reka-ui only re-highlights the first item when the collection goes from
empty to non-empty. With `create-item`, the create item is always
registered so the count never drops to 0, leaving the highlight stale
when async `items` load. This makes Enter create instead of selecting
the first option (or fall through to TagsInput's internal add).

Re-highlight the first item when `items` change while the menu is open,
waiting an extra tick so freshly mounted items are registered in
reka-ui's collection first.

Resolves #5974

Co-authored-by: lorado <4480983+lorado@users.noreply.github.com>
@github-actions github-actions Bot added the v4 #4488 label Jun 2, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes stale highlight behavior in InputMenu and SelectMenu when items change dynamically while the menu is open. Both components now track their open state via an internal isOpen ref and install a watcher on props.items that re-highlights the first option after a tick when items update. Implementation uses template refs (comboboxRootRef) bound to the Combobox root and calls highlightFirstItem() on it. Test cases verify the fix works with createItem: 'always' and async item loading.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing re-highlighting of the first item in InputMenu/SelectMenu when items change.
Linked Issues check ✅ Passed The PR successfully addresses issue #5974 by implementing automatic re-highlighting of the first item when items change while the menu is open, solving both reported problems.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the stale highlight issue: component logic updates and corresponding regression tests for the async-items + create-item flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The pull request description clearly relates to the changeset, detailing a bug fix for stale highlighting in InputMenu and SelectMenu components when async items load with create-item enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/input-select-menu-create-highlight

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/runtime/components/InputMenu.vue`:
- Around line 539-550: The watcher that calls
comboboxRootRef.value?.highlightFirstItem?.() should special-case
props.createItemPosition === 'top' so it highlights the first non-create option
instead of the "Create" item; update the watcher (the async function watching ()
=> props.items) to, after await nextTick(), check props.createItemPosition and
if it's 'top' find the first index in props.items that is not the create entry
and call the combobox API to highlight that index (or fall back to
highlightFirstItem() when createItemPosition !== 'top' or no separate index API
exists); also remove any lingering comment/guard about autocomplete methods
since comboboxRootRef.value?.highlightFirstItem?.() is safe with
AutocompleteRoot in reka-ui 2.9.8.

In `@src/runtime/components/SelectMenu.vue`:
- Around line 497-508: The watch currently always calls
comboboxRootRef.value?.highlightFirstItem(), which re-highlights the persistent
create-item when createItemPosition === 'top'; update the watch to detect when
createItemPosition === 'top' and in that case highlight the first non-create
option instead of blindly calling highlightFirstItem() — e.g. use
comboboxRootRef to inspect the registered items, find the first item that is not
the create-item (or skip items with the create-item marker), and call the
combobox highlight method for that item (or a highlight-by-index helper) so
async-loaded options get the correct focus while keeping the existing behavior
for bottom placement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 548dd77e-cdef-4ba4-9046-764fb2373c23

📥 Commits

Reviewing files that changed from the base of the PR and between ad7b54e and 859c16c.

📒 Files selected for processing (4)
  • src/runtime/components/InputMenu.vue
  • src/runtime/components/SelectMenu.vue
  • test/components/InputMenu.spec.ts
  • test/components/SelectMenu.spec.ts

Comment on lines +539 to +550
// reka-ui only re-highlights the first item when the list goes from empty to non-empty.
// With `create-item`, the create item is always registered so the count never drops to 0,
// leaving the highlight stale when async `items` load. Re-highlight when items change while open.
// Wait an extra tick so freshly mounted items are registered in reka-ui's collection before highlighting.
watch(() => props.items, async () => {
if (!isOpen.value) {
return
}

await nextTick()
comboboxRootRef.value?.highlightFirstItem?.()
}, { flush: 'post' })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does reka-ui 2.9.8 AutocompleteRoot expose a highlightFirstItem method like ComboboxRoot?

💡 Result:

Yes, in Reka UI version 2.9.8, the AutocompleteRoot component exposes a highlightFirstItem method, similar to the ComboboxRoot component [1]. Based on the Reka UI codebase, the AutocompleteRoot implementation includes a defineExpose block that specifically exposes several methods, including highlightFirstItem, highlightItem, and highlightSelected [1]. These methods are bound to the underlying primitive element's corresponding functions, allowing for imperative control over the highlighted item within the autocomplete component [1]. This pattern matches the implementation found in ComboboxRoot, which also provides these imperative methods for managing highlighted states [1][2][3].

Citations:


Handle createItemPosition="top" and remove unnecessary autocomplete-method concern

  • highlightFirstItem() re-highlights the first entry in reka-ui’s collection; when createItemPosition === 'top', the “Create” item is registered first, so this watcher will re-highlight “Create” rather than the first loaded option. Please confirm the intended behavior for the top configuration (or adjust the logic to target the first non-create option).
  • The optional call to comboboxRootRef?.highlightFirstItem?.() is safe in both modes: in reka-ui 2.9.8, AutocompleteRoot also exposes highlightFirstItem.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/runtime/components/InputMenu.vue` around lines 539 - 550, The watcher
that calls comboboxRootRef.value?.highlightFirstItem?.() should special-case
props.createItemPosition === 'top' so it highlights the first non-create option
instead of the "Create" item; update the watcher (the async function watching ()
=> props.items) to, after await nextTick(), check props.createItemPosition and
if it's 'top' find the first index in props.items that is not the create entry
and call the combobox API to highlight that index (or fall back to
highlightFirstItem() when createItemPosition !== 'top' or no separate index API
exists); also remove any lingering comment/guard about autocomplete methods
since comboboxRootRef.value?.highlightFirstItem?.() is safe with
AutocompleteRoot in reka-ui 2.9.8.

Comment on lines +497 to +508
// reka-ui only re-highlights the first item when the list goes from empty to non-empty.
// With `create-item`, the create item is always registered so the count never drops to 0,
// leaving the highlight stale when async `items` load. Re-highlight when items change while open.
// Wait an extra tick so freshly mounted items are registered in reka-ui's collection before highlighting.
watch(() => props.items, async () => {
if (!isOpen.value) {
return
}

await nextTick()
comboboxRootRef.value?.highlightFirstItem?.()
}, { flush: 'post' })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Same createItem top-position edge case as InputMenu.

highlightFirstItem() targets the first registered collection item, so when createItemPosition === 'top' (lines 672, 687‑688) the create item is highlighted again instead of the first async-loaded option, leaving the stale highlight unresolved for that configuration. The default bottom placement behaves correctly. Flagging here so the limitation is tracked consistently across both components.

Also applies to: 590-590

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/runtime/components/SelectMenu.vue` around lines 497 - 508, The watch
currently always calls comboboxRootRef.value?.highlightFirstItem(), which
re-highlights the persistent create-item when createItemPosition === 'top';
update the watch to detect when createItemPosition === 'top' and in that case
highlight the first non-create option instead of blindly calling
highlightFirstItem() — e.g. use comboboxRootRef to inspect the registered items,
find the first item that is not the create-item (or skip items with the
create-item marker), and call the combobox highlight method for that item (or a
highlight-by-index helper) so async-loaded options get the correct focus while
keeping the existing behavior for bottom placement.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 2, 2026

npm i https://pkg.pr.new/@nuxt/ui@6538

commit: 859c16c

@benjamincanac benjamincanac merged commit 0414dd0 into v4 Jun 3, 2026
24 checks passed
@benjamincanac benjamincanac deleted the fix/input-select-menu-create-highlight branch June 3, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InputMenu as autocomplete (dynamic options + create)

1 participant