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 EuiButtonGroup a11y and remove EuiToggle/EuiButtonToggle #4056

Merged
merged 36 commits into from
Oct 16, 2020

Conversation

cchaos
Copy link
Contributor

@cchaos cchaos commented Sep 19, 2020

Replacement for #3099 and closes #3023

... and closes #4036

⚠️ Breaking: Removed EuiToggle & EuiButtonToggle

The EuiToggle component wasn't appropriately handling the accessibility of how a toggle should behave. It was replaced in EUI components with correct implementations and there's little to none usages outside of EUI, so it is safe to remove.

This PR also removes the EuiButtonToggle because it was using the EuiToggle component. Instead, we now support a quick addition of the appropriate aria-pressed via the isSelected prop on all our button components.

Screen Shot 2020-10-14 at 5 42 02 PM

Upgrade path

  • EuiToggle didn't come with any styles or other visual indications. Consider whether you're replicating EuiSwitch, EuiRadio, EuiCheckbox, or EuiButton (as a toggle) behavior and use the appropriate component.
  • Simple EuiButtonToggle instances should be replaced with EuiButton. Moving label to be the children.
  • If your EuiButtonToggle is of iconOnly, simply swap to using an EuiButtonIcon.
  • If your EuiButtonToggle is of isEmpty , simply swap to using an EuiButtonEmpty.

All button replacements should address the toggle functionality in one of the two ways listed above:

  1. If your button changes its readable text, via children or aria-label, then there is no additional accessibility concern.
  2. If your button only changes the visual appearance, you must add aria-pressed passing a boolean for the on and off states. All 3 button types (will) provides a helper prop for this called isSelected.

Re-built the entire EuiButtonGroup component

The two main concepts brought over from #3099 are:

1. Use a <button aria-pressed="true or false"> for multiple selection groups

This is the preferred method for signifying whether a single button is on or off (pressed). Multi-selection groups are just a visually grouped button set all with their own state but under one legend.

Screen Shot 2020-10-12 at 14 43 26 PM

Screen Shot 2020-10-12 at 14 43 30 PM

2. Use a <input type="radio"> for single selection groups

Since only one button can be selected at a time for single selection groups, we make these behave as radio groups by actually using hidden radio groups. However, instead of trying to sync selection of a hidden input with the display, the element rendered by EuiButtonDisplay is a <label> connected to the input as is done in plain HTML.

Screen Shot 2020-10-12 at 14 44 21 PM

Screen Shot 2020-10-12 at 14 44 26 PM

Screen Shot 2020-10-12 at 14 44 34 PM

Both of these button group types are established in the new EuiButtonGroupButton component since they share more props/similarities than differences so it's easier to maintain.

3. Additional required props

In addition to changing the actual buttons that are rendered, a few props are now necessary for the accessibility features to work properly.

  • legend: Required to label the whole group with a single heading. Will be visibly hidden.
  • name: Optional for single selections. Applies to the name attribute of the inputs to keep them grouped. This cannot be the same as legend because of naming collisions. Will generate an string by default.
  • idSelected: Required for single selections because radio groups must have an option always selected.

Other (quick) changes

i. Added minWidth prop to EuiButton

There have been consumer situations where the min-width is not ideal and so this new prop allows consumers to quickly override this CSS property with an inline style.
Screen Shot 2020-10-12 at 12 24 28 PM

ii. Added baseClassName to EuiButtonDisplay

Before, EuiButtonDisplay was only used by EuiButton which made it ok to hard-code the euiButton class, but now it's being used directly by EuiButtonGroupButton which wanted to provide it's own base class that all the variations are built on.

EuiButton still produces all the same class lists it did before, but now EuiButtonDisplay is just more reusable (but still for internal use only).

iii. Updated EuiButton disabled styles to be based on a class and not :disabled

Because EuiButton can now render as something other than a <button>, we want to ensure that the disabled styles are applied, so the mixins now are based on .euiButton-isDisabled instead of :disabled.

Checklist

  • Check against all themes for compatibility in both light and dark modes
  • Checked in mobile
  • Checked in Chrome, Safari, Edge, and Firefox
  • Props have proper autodocs
  • Added documentation
  • Checked Code Sandbox works for the any docs examples
  • Added or updated jest tests
  • Checked for breaking changes and labeled appropriately
  • Checked for accessibility including keyboard-only and screenreader modes
  • A changelog entry exists and is marked appropriately

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

And using it in EuiButtonEmpty and EuiButtonIcon
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@cchaos cchaos changed the title Fix EuiButtonGroup a11y and remove EuiToggle Fix EuiButtonGroup a11y and remove EuiToggle/EuiButtonToggle Oct 15, 2020
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

Copy link
Contributor

@myasonik myasonik left a comment

Choose a reason for hiding this comment

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

a11y seems great, docs seem clear, 🚀 ship it!

One possible enhancement (can be ignored, added now, or added in a future issue): of isSelected is passed in, should that change any default styles? Could adjust fill state for you so that consumers don't have to pass in two props of the same value.

src-docs/src/views/button/button_example.js Outdated Show resolved Hide resolved
@cchaos
Copy link
Contributor Author

cchaos commented Oct 15, 2020

Could adjust fill state for you so that consumers don't have to pass in two props of the same value.

I had thought of this too, but that's not typically how we want the fill visual to indicate. Usually, fill should be reserved to promote the primary action for a page, not the selected. Though I understand that's a bit conflicty with our group styles, but I also consider that large button groups are also probably the primary action. So 🤷 I think it's better for the consumer to decide.

Co-authored-by: Michail Yasonik <michail@yasonik.com>
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@chandlerprall
Copy link
Contributor

jenkins test this

@chandlerprall
Copy link
Contributor

If we're relying on the documentation to communicate this functionality, I'm not sure it's worth having the custom isSelected prop compared to having devs specify aria-pressed directly. isSelected is also less clear when reading through existing code - my first thought would be that it visually modifies the button, if we force devs to use aria-pressed instead that obfuscation goes away.

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

@cchaos
Copy link
Contributor Author

cchaos commented Oct 16, 2020

Well actually with the addition of the isSelected prop and prop documentation, we don't have to solely rely on documentation. The prop is now discoverable through IDE auto-completion and the prop comment describes is use-case (and caveat).

Also, this prop name aligns with the EuiButtonGroup's selection prop of isSelected as well, so there's some consistency there. I realized it also simplifies the EuiButtonGroupButton usage, updating now.

The other nice thing is that it gives us a scalable prop to add more functionality as a "toggle" button if we need it in the future.

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4056/

Copy link
Contributor

@chandlerprall chandlerprall left a comment

Choose a reason for hiding this comment

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

Changes LGTM; pulled & tested locally, including keyboard nav & screen reader support

@cchaos cchaos merged commit 9e55637 into elastic:master Oct 16, 2020
@cchaos cchaos deleted the a11y/button_group branch October 16, 2020 16:57
kshitij86 added a commit to kshitij86/eui that referenced this pull request Nov 29, 2020
…#4056)

* [EuiButton] add `minWidth` prop
* Adding text shift to button and fix DataGrid usage and other tests
* [Breaking] Removing EuiToggle
* [Breaking] Removed EuiButtonToggle in favor of EuiButton.isSelected
@cchaos cchaos mentioned this pull request Jun 11, 2021
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants