Skip to content

fix(checkbox,radio,toggle): add missing keyboard focus indicators - #31295

Open
ShaneK wants to merge 17 commits into
mainfrom
FW-7585-FW-7586
Open

fix(checkbox,radio,toggle): add missing keyboard focus indicators#31295
ShaneK wants to merge 17 commits into
mainfrom
FW-7585-FW-7586

Conversation

@ShaneK

@ShaneK ShaneK commented Jul 24, 2026

Copy link
Copy Markdown
Member

Issue number: internal


What is the current behavior?

Currently, ion-checkbox and ion-toggle never show a keyboard focus indicator. ion-checkbox doesn't set the ion-focusable class and has no focus styles in the ios or md themes, so it can't receive the ion-focused class or render a ring. ion-toggle's only focus rule (:host(.ion-focused) input) targets the native input, which is display: none, so it never renders.

Separately, ion-checkbox, ion-radio, and ion-toggle show no focus indicator inside an ion-item that holds more than one input. ion-checkbox and ion-radio disable their own indicator in an item on the assumption the item draws one, but a multi-input item has no cover to highlight, so nothing is focused.

What is the new behavior?

ion-checkbox now sets ion-focusable when it isn't deferring to an item, with matching ios and md focus styles, so a standalone checkbox shows the same indicator ion-radio already did. Both ion-checkbox and ion-radio also become focusable inside a multi-input item, detected through the item's item-multiple-inputs class, so each control shows its own indicator when the item can't.

ion-toggle always shows its own indicator. Unlike checkbox and radio, it's excluded from the item's input cover, so an item never highlights on its behalf, in or out of a multi-input item. Its dead input focus rule is replaced with a ring on the visible track in both themes.

Does this introduce a breaking change?

  • Yes
  • No

Other information

Preview checkbox:

Preview toggle:

Preview radio:

@ShaneK
ShaneK requested a review from a team as a code owner July 24, 2026 18:01
@ShaneK
ShaneK requested a review from gnbm July 24, 2026 18:01
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Jul 28, 2026 4:03pm

Request Review

@github-actions github-actions Bot added the package: core @ionic/core package label Jul 24, 2026

@brandyscarney brandyscarney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good! My main feedback is we should be hiding the browser's native focus ring.

Comment thread core/src/components/radio/radio.tsx
Comment thread core/src/components/checkbox/checkbox.scss
Comment thread core/src/components/toggle/toggle.scss

@brandyscarney brandyscarney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code itself looks great! My requests are just for additional screenshots & some test changes.

Comment thread core/src/components/checkbox/test/item/index.html
Comment thread core/src/components/radio/test/item/index.html Outdated
Comment thread core/src/components/checkbox/test/item/index.html
Comment thread core/src/components/radio/test/item/index.html
Comment thread core/src/components/radio/radio.tsx
Comment thread core/src/components/checkbox/test/basic/checkbox.e2e.ts
Comment thread core/src/components/toggle/test/basic/toggle.e2e.ts

@brandyscarney brandyscarney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great work! Thanks for adding more tests/screenshots. 🎉

Comment on lines +290 to +293
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/

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.

Just a nit for consistency

Suggested change
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/
/**
* This behavior does not vary across directions
*/

Comment on lines +149 to +152
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/

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.

Suggested change
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/
/**
* This behavior does not vary across directions
*/

// iOS Checkbox: Keyboard Focus
// -----------------------------------------

:host(.ion-focused) .native-wrapper::after {

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.

All but one line of this is the same for md. Please move those over to checkbox.scss. By combining it now, it makes it easier for the Modular Ionic work.

// Material Design Checkbox: Keyboard Focus
// -----------------------------------------

:host(.ion-focused) .native-wrapper::after {

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.

$checkbox-ios-icon-checkmark-width: 1.5px;

/// @prop - Background color of focus indicator for checkbox when focused
$checkbox-ios-background-color-focused: ion-color(primary, tint);

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.

Since this is the same as md, let's move it to checkbox.vars.scss. By combining it now, it makes it easier for the Modular Ionic work.

$checkbox-md-transition-easing: cubic-bezier(.4, 0, .2, 1);

/// @prop - Background color of focus indicator for checkbox when focused
$checkbox-md-background-color-focused: ion-color(primary, tint);

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.

Comment on lines +4 to +7
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/

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.

Suggested change
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/
/**
* This behavior does not vary across directions
*/

Comment on lines +103 to +106
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/

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.

Suggested change
/**
* The focus indicator UI differs between iOS and MD, so these visual tests run
* in both modes. Direction does not affect the indicator, so only LTR is run.
*/
/**
* This behavior does not vary across directions
*/

// The item toggles `item-multiple-inputs` after this control renders and as
// inputs are added or removed. Re-render when it flips so the focus
// indicator stays in sync.
const item = this.el.closest('ion-item');

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.

Since this logic is the same as checkbox, is it possible to create a util?

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

Labels

package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants