diff --git a/.changeset/curly-phones-burn.md b/.changeset/curly-phones-burn.md
new file mode 100644
index 0000000000..8e273bce36
--- /dev/null
+++ b/.changeset/curly-phones-burn.md
@@ -0,0 +1,5 @@
+---
+'@primer/view-components': patch
+---
+
+[SelectPanel] Fix tab index issue in multi-select mode
diff --git a/app/components/primer/alpha/select_panel_element.ts b/app/components/primer/alpha/select_panel_element.ts
index f450a1e86c..af1396bf70 100644
--- a/app/components/primer/alpha/select_panel_element.ts
+++ b/app/components/primer/alpha/select_panel_element.ts
@@ -314,11 +314,7 @@ export class SelectPanelElement extends HTMLElement {
const itemContent = this.#getItemContent(item)
if (!itemContent) continue
- if (!this.isItemHidden(item) && !setZeroTabIndex) {
- setZeroTabIndex = true
- } else {
- itemContent.setAttribute('tabindex', '-1')
- }
+ itemContent.setAttribute('tabindex', '-1')
//
elements should not themselves be tabbable
item.removeAttribute('tabindex')
@@ -742,6 +738,8 @@ export class SelectPanelElement extends HTMLElement {
return true
}
+ if (!this.bannerErrorElement) return false
+
return !this.bannerErrorElement.hasAttribute('hidden')
}
diff --git a/test/system/alpha/select_panel_test.rb b/test/system/alpha/select_panel_test.rb
index 9ce82caffc..1eb60d4644 100644
--- a/test/system/alpha/select_panel_test.rb
+++ b/test/system/alpha/select_panel_test.rb
@@ -82,6 +82,21 @@ def wait_for_dialog_ready
end
def filter_results(query:)
+ input = find("input")
+
+ # If the query is an empty string or nil, using fill_in does not
+ # trigger the right type of input event, which in turn prevents
+ # the remote-input element from firing its remote-input-success
+ # event. Instead we have to focus on the input field, select all
+ # the text, and press backspace. Doing so fires the right type of
+ # event and clears the input.
+ if query.blank?
+ old_active_element = active_element
+ input.evaluate_script("this.focus()")
+ keyboard.type([:control, "a"], :backspace)
+ old_active_element.evaluate_script("this.focus()")
+ end
+
find("input").fill_in(with: query)
end
@@ -1052,6 +1067,21 @@ def test_arrowing_skips_filtered_items
end
end
+ def test_can_tab_to_first_item_after_filtering
+ visit_preview(:local_fetch)
+
+ click_on_invoker_button
+
+ filter_results(query: "2")
+ assert_selector "select-panel ul li", count: 1
+
+ filter_results(query: "")
+ keyboard.type(:tab)
+ assert_equal active_element.text, "Item 1"
+ end
+
+ ########## FORM TESTS ############
+
def test_single_select_form
visit_preview(:single_select_form, route_format: :json)