Skip to content

Checkbox accessibility#2624

Open
SaiYugandhar03 wants to merge 8 commits into
siemens:mainfrom
SaiYugandhar03:checkbox-accessibility
Open

Checkbox accessibility#2624
SaiYugandhar03 wants to merge 8 commits into
siemens:mainfrom
SaiYugandhar03:checkbox-accessibility

Conversation

@SaiYugandhar03

@SaiYugandhar03 SaiYugandhar03 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

💡 What is the current behavior?

The screen reader does not properly announce checkbox state changes (checked/unchecked) when users navigate to the checkbox using the Tab key and interact with it using the Enter or Space key.

Jira-ticket: IX-4335

🆕 What is the new behavior?

The screen reader correctly announces checkbox state changes (checked/unchecked) when the user navigates to the checkbox using the Tab key and activates it with the Enter or Space key.

🏁 Checklist

A pull request can only be merged if all of these conditions are met (where applicable):

  • 🦮 Accessibility (a11y) features were implemented
  • 🗺️ Internationalization (i18n) - no hard coded strings
  • 📲 Responsiveness - components handle viewport changes and content overflow gracefully
  • 📕 Add or update a Storybook story
  • 📄 Documentation was reviewed/updated siemens/ix-docs
  • 🧪 Unit tests were added/updated and pass (pnpm test)
  • 📸 Visual regression tests were added/updated and pass (Guide)
  • 🧐 Static code analysis passes (pnpm lint)
  • 🏗️ Successful compilation (pnpm build, changes pushed)

👨‍💻 Help & support

Summary by CodeRabbit

  • New Features
    • Added keyboard toggling for checkboxes using the Enter key.
  • Bug Fixes
    • Improved focus visibility for checkboxes on keyboard navigation.
    • Updated checkbox behavior and accessibility so the native checkbox input reflects state reliably.
  • Tests
    • Refreshed checkbox tests to assert the native input’s disabled/checked state and accessibility interactions directly.

@netlify

netlify Bot commented Jun 25, 2026

Copy link
Copy Markdown

Deploy Preview for ix-storybook ready!

Name Link
🔨 Latest commit 2efe5da
🔍 Latest deploy log https://app.netlify.com/projects/ix-storybook/deploys/6a437ce3f191410008ebb270
😎 Deploy Preview https://deploy-preview-2624--ix-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 2efe5da

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1feafbd8-8568-4397-8bbe-d47c778dd13b

📥 Commits

Reviewing files that changed from the base of the PR and between 76aae5e and 2efe5da.

📒 Files selected for processing (1)
  • packages/core/src/components/checkbox/tests/checkbox.ct.ts

📝 Walkthrough

Walkthrough

The checkbox component now styles focus through an absolutely positioned native input, adds Enter-key toggling in the component, and updates the checkbox tests to interact with and assert on the nested input.

Changes

Checkbox keyboard and focus handling

Layer / File(s) Summary
Focus outline via native input positioning
packages/core/src/components/checkbox/checkbox.scss
Replaces the hidden input and direct button focus outline with an absolutely positioned input and an adjacent-button :focus-visible outline rule.
Enter key toggle and test updates
packages/core/src/components/checkbox/checkbox.tsx, packages/core/src/components/checkbox/tests/checkbox.ct.ts
Adds a private Enter-key handler on the checkbox input and updates Playwright checks to query the nested native input, assert its checked and disabled state, and drive the accessibility test with Enter.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • siemens/ix#2620: Modifies ix-checkbox internal markup and focus-visible styling in the same component area.

Suggested reviewers

  • danielleroux

Poem

🐇 I found a checkbox, neat and bright,
Its focus hops with gentle light.
Press Enter once, and there it goes,
A tiny toggle tip-toes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the PR’s main goal: improving checkbox accessibility and keyboard interaction.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request adds accessibility attributes (role, aria-checked, and aria-label) to the internal button of the checkbox component and updates the corresponding tests to use a CSS selector. The reviewer identified that these changes introduce accessibility issues, such as duplicate roles and multiple tab stops, which compromise the accessibility tree and break standard Playwright queries. The feedback recommends hiding the internal button from assistive technologies using tabIndex={-1} and aria-hidden="true", and reverting the test to use the standard getByRole query.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +208 to +210
role="checkbox"
aria-checked={a11yBoolean(this.checked)}
aria-label={this.label}

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.

high

Adding role="checkbox", aria-checked, and aria-label to the internal <button> element introduces several accessibility issues:

  1. Duplicate/Nested Roles: The component now exposes multiple elements with role="checkbox" (the <Host> element, the native <input type="checkbox">, and the <button>). Nested interactive roles are invalid ARIA and cause screen readers to behave unpredictably.
  2. Multiple Tab Stops: Since both the native <input> and the <button> are focusable by default, keyboard users will encounter two tab stops for a single checkbox.
  3. Broken Accessibility Queries: This change broke the standard Playwright accessibility query page.getByRole('checkbox', { name: 'Accept Terms' }) in the tests, forcing a fallback to a specific CSS selector. This is a strong indicator that the accessibility tree is compromised.

Recommendation

Instead of making the <button> an interactive checkbox, the native <input type="checkbox"> should be the sole focusable and interactive element for assistive technologies. The visual container should be hidden from the accessibility tree using tabIndex={-1} and aria-hidden="true" so that screen readers and keyboard navigation ignore it entirely.

Suggested change
role="checkbox"
aria-checked={a11yBoolean(this.checked)}
aria-label={this.label}
tabIndex={-1}
aria-hidden="true"

Comment on lines +129 to +131
const checkbox = page
.locator('ix-checkbox')
.locator('button[role="checkbox"]');

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.

medium

Once the duplicate role="checkbox" is removed from the internal <button> element, we can revert this test to use the standard and more robust getByRole query. Testing via accessible roles and names is highly preferred over implementation-specific CSS selectors as it ensures the component remains accessible to assistive technologies.

    const checkbox = page.getByRole('checkbox', { name: 'Accept Terms' });

@SaiYugandhar03 SaiYugandhar03 marked this pull request as ready for review June 30, 2026 06:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/checkbox/checkbox.scss`:
- Around line 42-49: The native checkbox in the checkbox.scss selector for
input[type='checkbox'] is still being painted, which can overlap the custom
button. Update the checkbox styling so the input remains focusable for the
&:focus-visible + button rule in checkbox.scss, but is visually hidden and
aligned to the custom control instead of relying on position: absolute alone.
Keep the change scoped to the checkbox input/button styling so the browser’s
native checkbox UI does not render over the custom box.

In `@packages/core/src/components/checkbox/checkbox.tsx`:
- Around line 104-109: The checkbox component is exposing two accessible
checkbox surfaces because `render()` still maps the host element to
`role="checkbox"` and `aria-checked` while keyboard handling now belongs to the
native input. Update `Checkbox.render()` (and any related host attrs) so the
host no longer presents itself as a checkbox, and keep the accessible name/state
on the native input only; verify any helpers like `handleKeyDown` and the input
wiring still drive the checked state correctly.

In `@packages/core/src/components/checkbox/tests/checkbox.ct.ts`:
- Around line 129-132: The checkbox test currently validates toggling via click
only, so it misses the new keyboard path. Update the existing `checkbox.ct.ts`
coverage to explicitly send an Enter key interaction on `ix-checkbox` and assert
the checked state changes through that path, ensuring the regression exercises
`handleKeyDown()` in `checkbox.tsx` rather than only pointer behavior. Keep the
assertion focused on the keyboard-triggered toggle and use the existing
`checkbox` locator so the test remains tied to the component behavior added in
this PR.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a5698859-23b2-41f5-90fd-1e6c4f748edc

📥 Commits

Reviewing files that changed from the base of the PR and between fa6a6aa and ef931d7.

📒 Files selected for processing (3)
  • packages/core/src/components/checkbox/checkbox.scss
  • packages/core/src/components/checkbox/checkbox.tsx
  • packages/core/src/components/checkbox/tests/checkbox.ct.ts

Comment thread packages/core/src/components/checkbox/checkbox.scss
Comment thread packages/core/src/components/checkbox/checkbox.tsx
Comment thread packages/core/src/components/checkbox/tests/checkbox.ct.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/checkbox/tests/checkbox.ct.ts`:
- Around line 126-131: The checkbox test is no longer validating accessibility
because it switches from an accessible role/name lookup to a direct DOM query.
Update the test in checkbox.ct.ts to use the existing accessibility-tree locator
for the “Accept Terms” checkbox (the role/name query used elsewhere in the
checkbox tests), then perform the Enter key interaction through that locator and
keep the checked assertion on the same accessible target.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 00ee8f23-9dce-4be5-a59e-68ebd5d83d5d

📥 Commits

Reviewing files that changed from the base of the PR and between ef931d7 and 76aae5e.

📒 Files selected for processing (3)
  • packages/core/src/components/checkbox/checkbox.scss
  • packages/core/src/components/checkbox/checkbox.tsx
  • packages/core/src/components/checkbox/tests/checkbox.ct.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/components/checkbox/checkbox.tsx

Comment thread packages/core/src/components/checkbox/tests/checkbox.ct.ts Outdated
@sonarqubecloud

Copy link
Copy Markdown

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.

1 participant