Skip to content

Fix export format select keyboard focus#2366

Open
web3blind wants to merge 1 commit into
suitenumerique:mainfrom
web3blind:fix/export-format-select-focus
Open

Fix export format select keyboard focus#2366
web3blind wants to merge 1 commit into
suitenumerique:mainfrom
web3blind:fix/export-format-select-focus

Conversation

@web3blind
Copy link
Copy Markdown

Summary

  • remove the decorative export format select arrow from the tab order
  • hide the arrow button from assistive technologies

Why

In the export modal, keyboard and screen reader users currently encounter a separate focus stop for the dropdown arrow even though the combobox itself is the interactive control. This adds noise and makes the modal harder to navigate.

Fixes #2342.

Checks

  • npx -y prettier@3.8.3 --check apps/impress/src/features/docs/doc-export/components/ModalExport.tsx
  • static assertion that the patch sets aria-hidden="true" and tabindex="-1"

Note: I did not run the full app test suite because dependencies are not installed in this checkout.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Review Change Stack

Walkthrough

The ModalExport component now implements an accessibility fix for the format selection dropdown. The component imports useEffect and useRef from React, then adds a ref-bound container around the format <Select> element. A useEffect hook queries the select's internal "open" button element and applies aria-hidden="true" and tabindex="-1" attributes to prevent it from appearing in keyboard navigation and screen reader announcements.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix export format select keyboard focus' clearly and concisely describes the main change: addressing keyboard navigation issues with the export format select component.
Description check ✅ Passed The description is directly related to the changeset, explaining why the arrow button should be hidden from assistive technologies and removed from the tab order to improve keyboard/screen reader navigation.
Linked Issues check ✅ Passed The code changes align with issue #2342 requirements: using useEffect and useRef to target the arrow button element and applying aria-hidden="true" and tabindex="-1" attributes to remove it from tab order and hide from assistive technologies.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the keyboard focus issue in the ModalExport component by targeting the format select's arrow button, with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e40f7840-29f4-43bc-9e7e-9b19bb347f15

📥 Commits

Reviewing files that changed from the base of the PR and between 4841d95 and 35a296d.

📒 Files selected for processing (1)
  • src/frontend/apps/impress/src/features/docs/doc-export/components/ModalExport.tsx

Comment on lines +70 to +77
useEffect(() => {
const toggleButton = formatSelectRef.current?.querySelector<HTMLElement>(
'.c__select__inner__actions__open',
);

toggleButton?.setAttribute('aria-hidden', 'true');
toggleButton?.setAttribute('tabindex', '-1');
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find export-modal tests and any assertions on the arrow/select attributes
fd -t f . | rg -i 'export' | rg -i 'spec|test|e2e'
rg -nP -C3 'c__select__inner__actions__open|aria-hidden|tabindex' \
  --glob '*.spec.*' --glob '*.test.*' --glob '*e2e*' --glob '*cypress*' --glob '*playwright*'

Repository: suitenumerique/docs

Length of output: 3831


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Check whether the internal Cunningham class is referenced anywhere in tests/code
rg -n --hidden --no-ignore-vcs 'c__select__inner__actions__open' . || true

# 2) Check for aria-hidden/tabindex assertions specifically in doc-export related e2e tests
rg -n --hidden --no-ignore-vcs \
  'doc-export|utils-export|app-impress/doc-export|ModalExport|Export' \
  src/frontend/apps/e2e/__tests__ || true

rg -n --hidden --no-ignore-vcs \
  'aria-hidden\s*=\s*["'\'']true["'\'']|aria-hidden|toHaveAttribute\(.+aria-hidden|tabindex\s*=\s*["'\'']-1["'\'']|toHaveAttribute\(.+tabindex' \
  src/frontend/apps/e2e/__tests__/app-impress/*.spec.* || true

# 3) Also check in app-impress tests/utils-export (if any)
rg -n --hidden --no-ignore-vcs \
  'aria-hidden\s*=\s*["'\'']true["'\'']|toHaveAttribute\(.+aria-hidden|tabindex\s*=\s*["'\'']-1["'\'']|toHaveAttribute\(.+tabindex' \
  src/frontend/apps/e2e/__tests__/app-impress/** || true

Repository: suitenumerique/docs

Length of output: 4640


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --hidden --no-ignore-vcs \
  "toHaveAttribute\\(.+aria-hidden|aria-hidden\\s*=\\s*['\"]true['\"]|toHaveAttribute\\(.+tabindex\\s*,\\s*['\"]-1['\"]|tabindex\\s*=\\s*['\"]-1['\"]" \
  src/frontend/apps/e2e/__tests__/app-impress/**/*.spec.* \
  || true

rg -n --hidden --no-ignore-vcs \
  "aria-hidden|tabindex" \
  src/frontend/apps/e2e/__tests__/app-impress/**/*.spec.* \
  || true

Repository: suitenumerique/docs

Length of output: 255


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="src/frontend/apps/e2e/__tests__/app-impress"

rg -n --hidden --no-ignore-vcs \
  --glob '*.spec.*' --glob '*.test.*' --glob '*e2e*' --glob '*cypress*' --glob '*playwright*' \
  'toHaveAttribute\(.+aria-hidden|aria-hidden\s*=\s*['\'']true['\'']|toHaveAttribute\(.+tabindex\s*,\s*['\'']-1['\'']|tabindex\s*=\s*['\'']-1['\'']' \
  "$base" || true

rg -n --hidden --no-ignore-vcs \
  --glob '*.spec.*' --glob '*.test.*' --glob '*e2e*' --glob '*cypress*' --glob '*playwright*' \
  '(aria-hidden|tabindex)' \
  "$base" || true

Repository: suitenumerique/docs

Length of output: 603


Guard Cunningham internal Select class + add a11y regression test

ModalExport.tsx sets aria-hidden="true" and tabindex="-1" by querying Cunningham’s internal DOM node via .c__select__inner__actions__open. If Cunningham changes the markup/class, both setAttribute calls will silently no-op and the toggle can re-enter the accessibility/focus flow.

  • Add an e2e/RTL regression test that asserts the toggle element has aria-hidden="true" and tabindex="-1" in the export modal.
  • Prefer a supported Cunningham Select API/prop to hide the toggle from a11y (or add a guard/fallback), rather than relying on the internal class.

Keeping the effect without a dependency array is reasonable so the attributes are re-applied across Cunningham re-renders.

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.

Export modal: combobox arrow button independently focusable

1 participant