diff --git a/e2e/studio/features/filter-bar.spec.ts b/e2e/studio/features/filter-bar.spec.ts index 279afffe8b3..09fc74545ae 100644 --- a/e2e/studio/features/filter-bar.spec.ts +++ b/e2e/studio/features/filter-bar.spec.ts @@ -149,8 +149,8 @@ test.describe('Filter Bar', () => { } }) - test('Tab selects column from dropdown', async ({ page, ref }) => { - const tableName = `${tableNamePrefix}_tab_col` + test('Tab exits filter bar to next DOM element', async ({ page, ref }) => { + const tableName = `${tableNamePrefix}_tab_exit` const columnName = 'name' await createTable(tableName, columnName, [{ name: 'Alice' }]) @@ -159,14 +159,16 @@ test.describe('Filter Bar', () => { await setupFilterBarPage(page, ref, toUrl(`/project/${ref}/editor?schema=public`)) await navigateToTable(page, ref, tableName) + await addFilter(page, ref, columnName, '=', 'Alice') + const freeformInput = getFilterBarInput(page) await freeformInput.click() - await freeformInput.fill(columnName) - await expect(page.getByTestId(`filter-menu-item-${columnName}`)).toBeVisible() + await expect(freeformInput).toBeFocused() + // Tab should exit the filter bar (freeform input should lose focus) await page.keyboard.press('Tab') - await expect(page.getByTestId(`filter-condition-${columnName}`)).toBeVisible() + await expect(freeformInput).not.toBeFocused() } finally { await dropTable(tableName) } @@ -784,27 +786,26 @@ test.describe('Filter Bar', () => { } }) - test('Tab selects dropdown value option', async ({ page, ref }) => { - const tableName = `${tableNamePrefix}_kb_tab` + test('Shift+Tab exits filter bar to previous DOM element', async ({ page, ref }) => { + const tableName = `${tableNamePrefix}_shifttab_exit` + const columnName = 'name' - await query( - `CREATE TABLE IF NOT EXISTS ${tableName} ( - id bigint generated by default as identity primary key, - is_active boolean - )` - ) - await query(`INSERT INTO ${tableName} (is_active) VALUES (true), (false)`) + await createTable(tableName, columnName, [{ name: 'Alice' }]) try { await setupFilterBarPage(page, ref, toUrl(`/project/${ref}/editor?schema=public`)) await navigateToTable(page, ref, tableName) - await selectColumnFilter(page, 'is_active') - await selectOperator(page, 'is_active', '=') + await addFilter(page, ref, columnName, '=', 'Alice') - await page.keyboard.press('Tab') + const freeformInput = getFilterBarInput(page) + await freeformInput.click() + await expect(freeformInput).toBeFocused() - await expect(page.getByTestId('filter-condition-is_active')).toBeVisible() + // Shift+Tab should exit the filter bar (freeform input should lose focus) + await page.keyboard.press('Shift+Tab') + + await expect(freeformInput).not.toBeFocused() } finally { await dropTable(tableName) } diff --git a/packages/ui-patterns/src/FilterBar/FilterCondition.tsx b/packages/ui-patterns/src/FilterBar/FilterCondition.tsx index f94ea8626db..8f7b2425a3f 100644 --- a/packages/ui-patterns/src/FilterBar/FilterCondition.tsx +++ b/packages/ui-patterns/src/FilterBar/FilterCondition.tsx @@ -246,6 +246,7 @@ export function FilterCondition({ disabled={isLoading} aria-label={`Operator for ${property.label}`} data-testid={`filter-operator-${property.name}`} + tabIndex={-1} /> {condition.operator || ' '} @@ -289,6 +290,7 @@ export function FilterCondition({ disabled={isLoading} aria-label={`Value for ${property.label}`} data-testid={`filter-value-${property.name}`} + tabIndex={-1} /> {localValue || ' '} diff --git a/packages/ui-patterns/src/FilterBar/hooks.ts b/packages/ui-patterns/src/FilterBar/hooks.ts index 45bd4de2237..aa42aa73db7 100644 --- a/packages/ui-patterns/src/FilterBar/hooks.ts +++ b/packages/ui-patterns/src/FilterBar/hooks.ts @@ -154,7 +154,7 @@ export function useHighlightNavigation( setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : 0)) return } - if (e.key === 'Enter' || e.key === 'Tab') { + if (e.key === 'Enter') { // Edge case: when a filter is highlighted, skip dropdown selection and let fallback handle it if (options?.skipEnterWhenFilterHighlighted) { if (fallbackKeyDown) fallbackKeyDown(e)