Skip to content

Commit

Permalink
fix(toggle): ensure onToggle still work with props['aria-labelledby'] (
Browse files Browse the repository at this point in the history
…#13057)

* fix(toggle): ensure onToggle still work with props['aria-labelledby']

* docs(toggle): clarify relationship between hideLabel and labelText

---------

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
  • Loading branch information
janhassel and tay1orjones authored Feb 7, 2023
1 parent 95075da commit fa8bb0e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
29 changes: 26 additions & 3 deletions packages/react/src/components/Toggle/Toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useControllableState } from '../../internal/useControllableState';
Expand All @@ -29,6 +29,7 @@ export function Toggle({
...other
}) {
const prefix = usePrefix();
const buttonElement = useRef(null);
const [checked, setChecked] = useControllableState({
value: toggled,
onChange: onToggle,
Expand Down Expand Up @@ -71,9 +72,27 @@ export function Toggle({
});

return (
<div className={wrapperClasses}>
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div
className={wrapperClasses}
onClick={
ariaLabelledby
? (e) => {
// the underlying <button> can only be activated by keyboard as it is visually hidden;
// therefore, if this event's target is the <button>, it had to be triggered by
// the keyboard event which already calls handleClick. if we wouldn't catch this, the
// onClick and onToggle functions would be called twice whenever the user activates the
// toggle by keyboard and props['aria-labelledby'] is passed.
if (buttonElement.current && e.target !== buttonElement.current) {
handleClick(e);
buttonElement.current.focus();
}
}
: null
}>
<button
{...other}
ref={buttonElement}
id={id}
className={`${prefix}--toggle__button`}
role="switch"
Expand Down Expand Up @@ -132,7 +151,11 @@ Toggle.propTypes = {
disabled: PropTypes.bool,

/**
* Specify whether the label should be hidden, or not
* If true, the side labels (props.labelA and props.labelB) will be replaced by
* props.labelText, so that the toggle doesn't render a top label. In order to fully
* hide any labels, you can use props['aria-labelledby'] to refer to another element
* that labels the toggle. props.labelText would no longer be required in that case
* and can therefore be omitted.
*/
hideLabel: PropTypes.bool,

Expand Down
6 changes: 4 additions & 2 deletions packages/styles/scss/components/toggle/_toggle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
.#{$prefix}--toggle__switch,
.#{$prefix}--toggle__button:not(:disabled):active
+ .#{$prefix}--toggle__label
.#{$prefix}--toggle__switch {
.#{$prefix}--toggle__switch,
.#{$prefix}--toggle:active .#{$prefix}--toggle__switch {
box-shadow: 0 0 0 1px $focus-inset, 0 0 0 3px $focus;
}

Expand Down Expand Up @@ -193,7 +194,8 @@
.#{$prefix}--toggle__switch,
.#{$prefix}--toggle__button:not(:disabled):active
+ .#{$prefix}--toggle__label
.#{$prefix}--toggle__switch {
.#{$prefix}--toggle__switch,
.#{$prefix}--toggle:active .#{$prefix}--toggle__switch {
@include high-contrast-mode('focus');
}
}

0 comments on commit fa8bb0e

Please sign in to comment.