From 00a0452705b0f044afdb05e233d5a5827090b8bd Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 1 Jun 2026 09:09:14 +0000 Subject: [PATCH] fix(site): allow tabbing through chat search results --- .../dialogs/ChatSearchDialog.stories.tsx | 28 +++++++++++++++++-- .../dialogs/ChatSearchResults.tsx | 4 +-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx index 24ffe62b86..320b4ddc8c 100644 --- a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx +++ b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx @@ -295,8 +295,8 @@ export const KeyboardNavigation: Story = { } await expect(resultsViewport).toHaveAttribute("tabindex", "-1"); - await expect(firstResult).toHaveAttribute("tabindex", "-1"); - await expect(secondResult).toHaveAttribute("tabindex", "-1"); + await expect(firstResult).toHaveAttribute("tabindex", "0"); + await expect(secondResult).toHaveAttribute("tabindex", "0"); await userEvent.keyboard("{ArrowUp}"); await expect(secondResult).toHaveAttribute("aria-selected", "true"); @@ -432,6 +432,30 @@ export const BooleanFilterPill: Story = { }, }; +export const SearchResultsAreTabbable: Story = { + play: async () => { + const body = within(document.body); + const searchInput = body.getByRole("combobox", { name: "Search chats" }); + + await userEvent.type(searchInput, "Fix"); + const firstResult = await body.findByRole("option", { + name: /Fix race condition in auth middleware/, + }); + const secondResult = await body.findByRole("option", { + name: /Fix flaky workspace search story/, + }); + await expect(firstResult).toHaveAttribute("tabindex", "0"); + await expect(secondResult).toHaveAttribute("tabindex", "0"); + + await userEvent.tab(); + await userEvent.tab(); + await expect(firstResult).toHaveFocus(); + + await userEvent.tab(); + await expect(secondResult).toHaveFocus(); + }, +}; + export const ParameterizedFilterPill: Story = { beforeEach: () => { spyOn(API.experimental, "getChats").mockResolvedValue(mockChats); diff --git a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchResults.tsx b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchResults.tsx index c49c900332..b4507db5ab 100644 --- a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchResults.tsx +++ b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchResults.tsx @@ -263,11 +263,11 @@ const ChatSearchResultRow: FC = ({ id={id} role="option" aria-selected={isSelected} - tabIndex={-1} + tabIndex={0} to={{ pathname: `/agents/${chat.id}`, search: location.search }} onClick={onSelect} className={cn( - "grid w-full min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-start gap-2 rounded-md px-1.5 py-1 text-content-secondary no-underline hover:bg-surface-tertiary/40 hover:text-content-primary", + "grid w-full min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-start gap-2 rounded-md px-1.5 py-1 text-content-secondary no-underline hover:bg-surface-tertiary/40 hover:text-content-primary focus-visible:outline focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-content-link", isSelected && "bg-surface-tertiary/40 text-content-primary", )} >