Skip to content

Commit

Permalink
fix(switch): fix screen reader announcements with new validation
Browse files Browse the repository at this point in the history
This fix amends the screen reader announcements with voiceOver in Safari, preventing "and x more
items" to be announced. Sets the input's accessible name as the label and accessible description to
the hint text and validation message if provided. This fix also addresses issue where required star
or (optional) did not appear on the label when set with the neww validation.

fix #6901
  • Loading branch information
nuria1110 committed Oct 9, 2024
1 parent 5700920 commit aed0ba0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/components/switch/switch-test.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ Default.args = {
value: "test-value",
disabled: false,
size: "small",
required: false,
isOptional: false,
};

export const NewDefault = ({
Expand Down Expand Up @@ -133,6 +135,8 @@ NewDefault.args = {
value: "test-value",
disabled: false,
size: "small",
required: false,
isOptional: false,
};

export const WithLongTextStrings = () => (
Expand Down
77 changes: 53 additions & 24 deletions src/components/switch/switch.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useContext } from "react";
import React, { useState, useCallback, useContext, useRef } from "react";
import { MarginProps } from "styled-system";

import StyledSwitch, { ErrorBorder, StyledHintText } from "./switch.style";
Expand All @@ -14,6 +14,7 @@ import NewValidationContext from "../carbon-provider/__internal__/new-validation
import ValidationMessage from "../../__internal__/validation-message/validation-message.component";
import Box from "../box";
import Label from "../../__internal__/label";
import guid from "../../__internal__/utils/helpers/guid";

export interface SwitchProps extends CommonCheckableInputProps, MarginProps {
/** Identifier used for testing purposes, applied to the root element of the component. */
Expand Down Expand Up @@ -57,6 +58,8 @@ export const Switch = React.forwardRef(
disabled,
loading,
reverse = true,
required,
isOptional,
validationOnLabel = false,
labelInline = false,
labelSpacing,
Expand All @@ -80,6 +83,10 @@ export const Switch = React.forwardRef(
const isControlled = checked !== undefined;
const { validationRedesignOptIn } = useContext(NewValidationContext);

const labelId = useRef(`${guid()}-label`);
const inputHintId = useRef(`${guid()}-hint`);
const validationMessageId = useRef(`${guid()}-message`);

const [checkedInternal, setCheckedInternal] = useState(
defaultChecked || false
);
Expand Down Expand Up @@ -161,6 +168,8 @@ export const Switch = React.forwardRef(
reverse: !reverse, // switched to preserve backward compatibility
validationOnLabel: shouldValidationBeOnLabel && !disabled,
ref,
required,
isOptional,
...rest,
};

Expand All @@ -186,8 +195,8 @@ export const Switch = React.forwardRef(

const inputPropsForNewValidation = {
autoFocus,
error,
warning,
// set aria-invalid but prevent validationIconId from being added to aria-describedby
error: !!error,
disabled: disabled || loading,
loading,
checked: isControlled ? checked : checkedInternal,
Expand All @@ -200,37 +209,57 @@ export const Switch = React.forwardRef(
type: "checkbox",
role: "switch",
ref,
required,
isOptional,
...rest,
};

const applyValidation = error || warning;

const ariaDescribedBy = [
labelHelp && inputHintId.current,
applyValidation && validationMessageId.current,
]
.filter(Boolean)
.join(" ");

return (
<>
{validationRedesignOptIn ? (
<StyledSwitch {...switchStylePropsForNewValidation}>
<Label>
<Box data-role="hint-text-wrapper" mb={labelHelp ? 0 : 1}>
{label}
{labelHelp && (
<StyledHintText data-role="hint-text">
{labelHelp}
</StyledHintText>
)}
</Box>
<Box position="relative">
<ValidationMessage error={error} warning={warning} />
{applyValidation && (
<ErrorBorder
data-role="error-border"
warning={!!(!error && warning)}
/>
)}
<CheckableInput {...inputPropsForNewValidation}>
<SwitchSlider {...switchSliderPropsForNewValidation} />
</CheckableInput>
</Box>
<Label
labelId={labelId.current}
disabled={disabled}
isRequired={required}
optional={isOptional}
>
{label}
</Label>
{labelHelp && (
<StyledHintText data-role="hint-text" id={inputHintId.current}>
{labelHelp}
</StyledHintText>
)}
<Box position="relative">
<ValidationMessage
error={error}
warning={warning}
validationId={validationMessageId.current}
/>
{applyValidation && (
<ErrorBorder
data-role="error-border"
warning={!!(!error && warning)}
/>
)}
<CheckableInput
ariaLabelledBy={`${label && labelId.current}`}
ariaDescribedBy={ariaDescribedBy}
{...inputPropsForNewValidation}
>
<SwitchSlider {...switchSliderPropsForNewValidation} />
</CheckableInput>
</Box>
</StyledSwitch>
) : (
<TooltipProvider
Expand Down
12 changes: 7 additions & 5 deletions src/components/switch/switch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -364,17 +364,19 @@ test("renders `labelHelp` as hint text when `validationRedesignOptIn` flag is tr
expect(screen.getByText("hint text")).toBeVisible();
});

// Required for coverage
test("renders the expected margin-bottom value when `labelHelp` is present", () => {
test("should render with correct accessible name and description when `validationRedesignOptIn` flag is true", () => {
render(
<CarbonProvider validationRedesignOptIn>
<Switch label="foo" labelHelp="hint text" warning="this is a warning" />
<Switch label="foo" labelHelp="hint text" error="this is an error" />
</CarbonProvider>
);

const hintTextWrapper = screen.getByTestId("hint-text-wrapper");
const switchElement = screen.getByRole("switch");

expect(hintTextWrapper).toHaveStyleRule("margin-bottom: var(--spacing000)");
expect(switchElement).toHaveAccessibleName("foo");
expect(switchElement).toHaveAccessibleDescription(
"hint text this is an error"
);
});

test("the expected translations are correctly applied for on", () => {
Expand Down

0 comments on commit aed0ba0

Please sign in to comment.