Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correct the display of checkbox read-only state #3328

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jawinn
Copy link
Collaborator

@jawinn jawinn commented Oct 25, 2024

Description

As noted in CSS-833, the CSS, SWC, and RSP implementations of read-only checkboxes/checkbox groups, and the docs surrounding them, conflicted with each other. After discussing with the design team, it was decided that the first step would be for CSS to bring our visual styles in line with React's implementation.

Field group:

  • This PR updates field group to remove the additional checkbox read-only styles that were causing the box to not display and for commas to be appended.
  • Template: added aria-labeledby connected to the group label, so this is announced as a group by the screen reader.

Checkbox:

  • Removes some unnecessary read-only CSS. Read-only just needs to override disabled styles. It was confirmed with PJ on the design team that otherwise it uses default styles (for both default and emphasized; React also displays this).
  • Template: The checkboxes are made sure to be shown as both focusable and immutable. Some JS was added to prevent the checkbox value from changing.
  • Template: disabled attribute removed when read-only. Read-only still needs to be focusable / in the tab order.
  • Template: Added aria-disabled="true" when read-only, so screen readers do not announce as a normal interactive checkbox. For VoiceOver, this will add "dimmed" now and won't announce the shortcut to check or uncheck. Note that I've not used aria-readonly like as seen in React Spectrum as it is not announced by the screen reader (any differently than a normal checkbox) and MDN states that it is "not relevant" for input with type checkbox.
  • Adds additional VRT tests to cover some missing combination of states

This also updates all of the docs surrounding these things and adds a new storybook Docs example for Checkbox. The field group usage notes have been cleaned up as well.

CSS-1004

How and where has this been tested?

Please tag yourself on the tests you've marked complete to confirm the tests have been run by someone other than the author.

Validation steps

  • Field group docs page: read-only example shows full checkbox with boxes and no added commas, and read-only colors
  • Checkbox docs page: read-only example shows full checkbox with boxes and no added commas, and read-only colors
  • Checkbox docs page: read-only default shows default colors and read-only emphasized shows emphasized colors (should include the blue, which is different than it was previously) @marissahuysentruyt
  • Checkbox testing preview: additional test cases appear and cover the usage of read-only @marissahuysentruyt
  • Review and proofread docs for both examples
  • Read-only checkbox is immutable in both docs and stories (clicking does not change checkedness)
  • Read-only checkboxes are focusable
  • Field group of checkboxes is announced as a group by screen reader (VoiceOver) @marissahuysentruyt
  • Read only checkboxes are announced as dimmed/disabled by screen reader @marissahuysentruyt

Regression testing

Expected changes:

  • Additional tests added
  • Read-only checked for emphasized now displays with blue
  • Field group read-only no longer shows comma display (see screenshots)

Validate:

  1. The documentation pages for at least two other components are still loading, including:
  • The pages render correctly, are accessible, and are responsive.
  1. If components have been modified, VRTs have been run on this branch:
  • VRTs have been run and looked at.
  • Any VRT changes have been accepted (by reviewer and/or PR author), or there are no changes.

Screenshots

Before:
Screenshot 2024-10-25 at 4 24 36 PM

After:
Screenshot 2024-10-25 at 4 26 27 PM

To-do list

  • I have read the contribution guidelines.
  • I have updated relevant storybook stories and templates.
  • I have tested these changes in Windows High Contrast mode.
  • If my change impacts documentation, I have updated the documentation accordingly.
  • ✨ This pull request is ready to merge. ✨

Copy link

changeset-bot bot commented Oct 25, 2024

🦋 Changeset detected

Latest commit: 67057d1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@spectrum-css/checkbox Patch
@spectrum-css/fieldgroup Minor

Not sure what this means? Click here to learn what changesets are.

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

Copy link
Contributor

github-actions bot commented Oct 25, 2024

🚀 Deployed on https://pr-3328--spectrum-css.netlify.app

Copy link
Contributor

github-actions bot commented Oct 25, 2024

File metrics

Summary

Total size: 4.30 MB*
Total change (Δ): 🟢 ⬇ 2.79 KB (-0.06%)

Table reports on changes to a package's main file. Other changes can be found in the collapsed Details section below.

Package Size Δ
checkbox 23.58 KB 🟢 ⬇ 0.64 KB
fieldgroup 1.37 KB 🟢 ⬇ 0.31 KB

Details

checkbox

Filename Head Compared to base
index-base.css 22.96 KB 🟢 ⬇ 0.64 KB (-2.67%)
index-theme.css 1.24 KB -
index-vars.css 23.58 KB 🟢 ⬇ 0.64 KB (-2.60%)
index.css 23.58 KB 🟢 ⬇ 0.64 KB (-2.60%)
themes/express.css 0.95 KB -
themes/spectrum.css 0.94 KB -

fieldgroup

Filename Head Compared to base
index-base.css 1.37 KB 🟢 ⬇ 0.31 KB (-17.98%)
index-vars.css 1.37 KB 🟢 ⬇ 0.31 KB (-17.98%)
index.css 1.37 KB 🟢 ⬇ 0.31 KB (-17.98%)
* Size determined by adding together the size of the main file for all packages in the library.
* Results are not gzipped or minified.
* An ASCII character in UTF-8 is 8 bits or 1 byte.

Copy link
Collaborator

@marissahuysentruyt marissahuysentruyt left a comment

Choose a reason for hiding this comment

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

Love this- the read-only checkboxes are focusable, but cannot be checked/unchecked. 👍 I love that you added a bunch of the documentation from the guidelines site- thank you!

I did have a question about the expectations for what would be announced by a screenreader in read-only cases. Maybe that's something that's part of the research on read-only that's coming up. When using voice over, a read-only checkbox is announced like any of the other non-disabled checkboxes, so how would a user know that they cannot change the selection? I would think this would probably be a bigger discussion involving all of our team and some accessibility folks, so I'm not going to let it block my approval right now. Just wondered if you had any knowledge I don't!

* A group of read-only checkboxes that have been checked. In U.S. English, use commas to delineate items within read-only checkbox groups. In other languages, use the locale-specific formatting.
* Implementations should include the following behavior for read-only checkboxes:
* - Read-only checkboxes are immutable, i.e. their checked state cannot be changed.
* - Unlike disabled checkbox groups, the normally focusable elements of a checkbox group should remain focusable.
*/
export const ReadOnly = Template.bind({});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think we should eventually add a "read-only radio group" to the docs page? I was wondering why field group only has "read-only checkboxes" on this page, since read-only radios exist too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That'd be a good idea for CSS-1005 that looks at this issue for radios.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Added in #3350

@jawinn jawinn marked this pull request as draft October 28, 2024 15:47
@marissahuysentruyt marissahuysentruyt dismissed their stale review October 28, 2024 19:42

I reviewed too early before the PR was ready.

@jawinn jawinn force-pushed the jawinn/css-1004-checkbox-readonly-refactor branch from 32a1113 to c2cac21 Compare October 29, 2024 17:49
@jawinn
Copy link
Collaborator Author

jawinn commented Oct 29, 2024

When using voice over, a read-only checkbox is announced like any of the other non-disabled checkboxes, so how would a user know that they cannot change the selection?

Good call-out. VoiceOver reads it the same way that you had heard, for React Spectrum's version that uses aria-readonly. I've updated this to use aria-disabled, which now announces it as "dimmed" and does not announce the keyboard shortcut to check/uncheck. See the updated PR notes about that.

@jawinn jawinn force-pushed the jawinn/css-1004-checkbox-readonly-refactor branch from c2cac21 to f1def57 Compare October 29, 2024 18:13
This removes some unnecessary read-only styles. Read-only just needs to
override disabled styles; otherwise it uses default styles (for both
default and emphasized).

Also adjusts template to include aria-disabled when in the read-only
state, so screen readers such as VoiceOver do not announce the input
as normal. Note that aria-readonly is not used as it is not announced
property and MDN states that it is "not relevant" for input with type
checkbox.
The previous display of the read-only state, without checkboxes and
displaying commas did not match up with any guidelines. This update is
to make the display of read-only match with what is implemented in
React Spectrum.

It also includes aria-labeledby in the template so the group is
announced by screen readers.
@jawinn jawinn force-pushed the jawinn/css-1004-checkbox-readonly-refactor branch from f1def57 to 67057d1 Compare October 29, 2024 18:30
@jawinn jawinn marked this pull request as ready for review October 29, 2024 18:34
@@ -46,6 +50,7 @@ export const Template = (
label,
isRequired,
alignment: labelPosition === "side" ? "right" : "top",
id: groupLabelId,
},
context,
),
Copy link
Collaborator

Choose a reason for hiding this comment

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

For the input loop, consider checking one of them to be able to test for sure the immutability. Here's how I did it for the radio update as one option.

@jawinn jawinn added the s1 label Oct 30, 2024
Copy link
Collaborator

@marissahuysentruyt marissahuysentruyt left a comment

Choose a reason for hiding this comment

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

I think this is looking good. The read-only behavior works as you described, VoiceOver is announcing the read-only checkboxes in a way that is distinct from other editable checkboxes, and field group no longer has those commas! Just a few things from me!

  • love all of the new tests you added
  • thanks for going so deep into the aria-labelled / aria-readonly / aria-disabled attributes. I might ping you for resources so I can keep those straight and know when to use them.

@@ -50,7 +50,7 @@ export const Template = ({
typeof size !== "undefined",
[`${rootClass}--emphasized`]: isEmphasized,
["is-indeterminate"]: isIndeterminate,
["is-disabled"]: isDisabled|| isReadOnly,
["is-disabled"]: isDisabled,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like that we were able to remove the isReadOnly arg from this. It immediately makes sense now to any newcomer to the codebase.

@@ -62,13 +62,19 @@ export const Template = ({
type="checkbox"
class="${rootClass}-input"
aria-labelledby=${ifDefined(ariaLabelledby)}
aria-disabled=${ifDefined(isReadOnly ? "true" : undefined)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can look it up on MDN, but I wonder why aria-disabled adds the "dimmed" part of the screen reader announcement, as opposed to just saying something like "read-only." 🤔

e.preventDefault();
e.target.checked = !e.target.checked;
}
if (isDisabled || isReadOnly) return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would we ever get to this "or" portion of the code, the || isReadOnly?

The code would run through the first if(isReadOnly), and if it's also disabled, it'll return anyways, but I guess my question is do we need the "or read only" in this if(isDisabled || isReadOnly) block. Could it run through both if blocks, if a read-only checkbox isn't disabled? Should the return just go in the if(isReadOnly) block?

@@ -27,6 +27,10 @@ export const CheckboxGroup = Variants({
testHeading: "Checked",
isChecked: true,
},
{
testHeading: "Indeterminate",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Great catch on all of the missing indeterminate tests!

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

Successfully merging this pull request may close these issues.

3 participants