Skip to content

fix: return focus to column filter after popup closes - #898

Open
fateeand wants to merge 6 commits into
masterfrom
896-table-tree-table-focus-is-lost-after-closing-a-column-filter-with-apply-clear-or-close
Open

fateeand wants to merge 6 commits into
masterfrom
896-table-tree-table-focus-is-lost-after-closing-a-column-filter-with-apply-clear-or-close

Conversation

@fateeand

@fateeand fateeand commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • When a column filter menu was closed with Apply, Clear (with hideOnClear) or Close (×), focus fell to <body>, because the focused button inside the menu was removed. TableColumnFilterComponent.hide() now returns focus to that column's filter button through CPS_FOCUS_SERVICE.focusElement(button, isKeyboard()), so the focus ring shows only after keyboard use. Without the focus service, it falls back to button.focus().
  • Focus is returned only when the menu was open and focus was either inside the menu or on <body>. <body> counts as inside the menu because Safari and Firefox on macOS don't focus clicked buttons, so clicking Apply, Clear or Close leaves focus on <body> there. Focus on any other element outside the menu is left alone. Esc and click-outside behave as before.
  • The check is in hide(), so the public hideFilter() on the cpsTColFilter / cpsTTColFilter directives behaves the same way. Calling it on an open menu while focus is on <body> moves focus to the filter button. Calling it on a closed menu doesn't move focus.
  • One shared component renders the filter for both cps-table and cps-tree-table, so this one change fixes both.
  • Unit tests, run once with Table and once with TreeTable, open the real menu and check that:
    • Apply, Clear and Close return focus to the filter button: with a focus ring after keyboard use, without one after a mouse click, and also when the click left focus on <body>;
    • hide() leaves focus alone when it's outside the menu or when the menu is already closed;
    • Esc still returns focus to the filter button.
  • Playwright tests for both tables: Apply by keyboard (focus returns and :focus-visible matches) and by mouse (focus returns and the ring is suppressed). Verified in Chromium and WebKit. In WebKit, the mouse-click test fails without the <body> handling.

Closes #896


Release notes:

  • fixed focus being lost after closing a table or tree table column filter with Apply, Clear or Close

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Coverage report for library

St.❔
Category Percentage Covered / Total
🟢 Statements 98.82% 7619/7710
🟢 Branches 93.92% 3939/4194
🟢 Functions 97.56% 1399/1434
🟢 Lines 99.34% 7069/7116

Test suite run success

3283 tests passing in 76 suites.

Report generated by 🧪jest coverage report action from 476e39e

Copilot AI left a comment

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.

🟡 Changes recommended

The core fix is sound, but a misleading click-outside test should be removed, and pointer users in Safari and Firefox on macOS may still lose focus.

1 open issue
What changed in this PR

This PR fixes a focus problem in the table and tree table column filters. When a user closes the filter menu with Apply, Clear (when hideOnClear is set), or Close, focus used to fall to <body> because the focused button was removed with the menu. TableColumnFilterComponent.hide() now moves focus back to that column's filter button when focus was inside the menu. Because cps-table and cps-tree-table share this component, one change fixes both. Esc and click-outside behavior are unchanged. The PR closes #896.

Changes:

  • hide() checks whether focus is inside the menu. If it is, focus moves to the filter button through CPS_FOCUS_SERVICE.focusElement(...), with a button.focus() fallback.
  • The filter button in the template gets a #filterMenuButton template reference.
  • Jest tests cover focus return for Apply, Clear, and Close, with and without a focus ring. Playwright tests cover Apply on both table types.
File Description
projects/​cps-ui-kit/​src/​lib/​components/​cps-table/​components/​internal/​table-column-filter/​table-column-filter.component.ts Adds the focus check in hide() and the helper that returns focus to the filter button.
projects/​cps-ui-kit/​src/​lib/​components/​cps-table/​components/​internal/​table-column-filter/​table-column-filter.component.spec.ts Adds Jest tests for focus return, focus ring behavior, and focus staying outside the menu.
projects/​cps-ui-kit/​src/​lib/​components/​cps-table/​components/​internal/​table-column-filter/​table-column-filter.component.html Adds the #filterMenuButton reference to the filter button.
playwright/​cps-ui-kit/​components/​cps-tree-table.spec.ts Adds end-to-end checks that tree table focus returns to the filter button after Apply, with and without keyboard use.
playwright/​cps-ui-kit/​components/​cps-table.spec.ts Adds the same end-to-end checks for cps-table.

Review effort: Lite

Copilot AI left a comment

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.

🟡 Changes recommended

The fix is small and well tested, but the PR description says focus outside the menu is left alone, while the code also returns focus when focus is on <body>, and this needs a code comment and a description update before merge.

1 open issue
1 resolved since last review

Review effort: Lite

Copilot AI left a comment

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.

🔵 Needs a closer look

The change alters focus handling in a shared component and in the public hideFilter() API, and the <body> case depends on browser-specific click behavior that needs human verification.

No open issues 🎉

1 resolved since last review

Review effort: Lite

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Playwright test results

passed  986 passed

Details

stats  986 tests across 35 suites
duration  35 minutes, 17 seconds
commit  476e39e
info  For details, download the Playwright report

lukasmatta
lukasmatta previously approved these changes Oct 28, 2026
await expect(filterBtn).toBeFocused();
expect(
await filterBtn.evaluate((el) => el.matches(':focus-visible'))
).toBe(true);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
).toBe(true);
).toBe(true);
await expect(filterBtn).not.toHaveClass(/suppress-focus-visible/);

nit: The test might pass even if the focus ring is not visible (:focus-visible still matches when the ring is suppressed via .suppress-focus-visible). We might want to assert suppression class not being present.

Same applies for cps-table.spec.ts:L95-97

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, thanks. Applied the suggestion

…losing-a-column-filter-with-apply-clear-or-close

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Table, Tree table: focus is lost after closing a column filter with Apply, Clear or Close

3 participants