Skip to content

Commit

Permalink
fix(toggle): make props.labelText optional (#13196)
Browse files Browse the repository at this point in the history
* fix(toggle): make props.labelText optional

* docs(toggle): add 'with accessible labels' story

* test(toggle): update public api snapshot

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
janhassel and kodiakhq[bot] authored Mar 3, 2023
1 parent 07168bf commit 5aff418
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8528,7 +8528,9 @@ Map {
"labelB": Object {
"type": "node",
},
"labelText": [Function],
"labelText": Object {
"type": "string",
},
"onClick": Object {
"type": "func",
},
Expand Down
9 changes: 7 additions & 2 deletions packages/react/src/components/Toggle/Toggle-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,15 @@ describe('Toggle', () => {
).toBe(props.labelText);
});

it("doesn't render sideLabel if props.hideLabel and props['aria-labelledby'] are provided", () => {
it("doesn't render sideLabel if props.hideLabel and no props.labelText is provided", () => {
const externalElementId = 'external-element-id';
wrapper.rerender(
<Toggle {...props} hideLabel aria-labelledby={externalElementId} />
<Toggle
{...props}
hideLabel
labelText={null}
aria-labelledby={externalElementId}
/>
);

expect(
Expand Down
25 changes: 8 additions & 17 deletions packages/react/src/components/Toggle/Toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export function Toggle({

const isSm = size === 'sm';
const sideLabel = hideLabel ? labelText : checked ? labelB : labelA;
const renderSideLabel = !(hideLabel && ariaLabelledby);
const LabelComponent = ariaLabelledby ? 'div' : 'label';
const renderSideLabel = !(hideLabel && !labelText);
const LabelComponent = labelText ? 'label' : 'div';

const wrapperClasses = classNames(
`${prefix}--toggle`,
Expand Down Expand Up @@ -76,7 +76,7 @@ export function Toggle({
<div
className={wrapperClasses}
onClick={
ariaLabelledby
!labelText
? (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
Expand Down Expand Up @@ -152,10 +152,7 @@ Toggle.propTypes = {

/**
* 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.
* props.labelText (if passed), so that the toggle doesn't render a top label.
*/
hideLabel: PropTypes.bool,

Expand All @@ -176,17 +173,11 @@ Toggle.propTypes = {

/**
* Provide the text that will be read by a screen reader when visiting this
* control. This is required unless 'aria-labelledby' is provided instead
* control. This should be provided unless 'aria-labelledby' is set instead
* or you use an external <label> element with its "for" attribute set to the
* toggle's id.
*/
labelText: (props, ...rest) => {
if (!props['aria-labelledby'] && !props.labelText) {
return new Error(
'labelText property is required if no aria-labelledby is provided.'
);
}

return PropTypes.node(props, ...rest);
},
labelText: PropTypes.string,

/**
* Provide an event listener that is called when the control is clicked
Expand Down
28 changes: 27 additions & 1 deletion packages/react/src/components/Toggle/Toggle.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

import React from 'react';

import { VStack } from '../Stack';
import Toggle from '../Toggle';

export default {
Expand Down Expand Up @@ -35,7 +37,7 @@ export const SmallToggle = () => (
);

export const Playground = (args) => (
<Toggle labelA="Off" labelB="On" defaultToggled id="toggle-1" {...args} />
<Toggle labelA="Off" labelB="On" defaultToggled id="toggle-3" {...args} />
);

Playground.argTypes = {
Expand Down Expand Up @@ -80,3 +82,27 @@ Playground.argTypes = {
},
},
};

export const WithAcessibleLabels = () => (
<VStack gap={7}>
<Toggle id="toggle-4" labelText="Toggle label" />

<Toggle id="toggle-5" labelText="Toggle label" hideLabel />

<div>
<div id="toggle-6-label" style={{ marginBlockEnd: '0.5rem' }}>
External toggle label
</div>
<Toggle id="toggle-6" aria-labelledby="toggle-6-label" hideLabel />
</div>

<div>
<label
htmlFor="toggle-7"
style={{ display: 'block', marginBlockEnd: '0.5rem' }}>
External toggle label
</label>
<Toggle id="toggle-7" hideLabel />
</div>
</VStack>
);

0 comments on commit 5aff418

Please sign in to comment.