Skip to content

Commit

Permalink
[a11y] Add screen reader indicator for invalid input (#1621)
Browse files Browse the repository at this point in the history
* Add screen reader indicator for invalid input field

* Update snapshot
  • Loading branch information
azimmerly committed Jun 23, 2022
1 parent f150250 commit a724a83
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 30 deletions.
13 changes: 9 additions & 4 deletions src/shared-components/field/__snapshots__/test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ exports[`<Field /> UI snapshots renders with errorMessage, hintMessage and hideM
class="emotion-2 emotion-3"
>
<input
aria-invalid="true"
class="emotion-4 emotion-5"
/>
<div
Expand All @@ -279,10 +280,14 @@ exports[`<Field /> UI snapshots renders with errorMessage, hintMessage and hideM
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="error"
>
<strong>
Uh Oh!
</strong>
Type again
<output
role="alert"
>
<strong>
Uh Oh!
</strong>
Type again
</output>
</li>
</ul>
</div>
Expand Down
10 changes: 9 additions & 1 deletion src/shared-components/field/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ export const Field: Field = ({
/>
);

const { id } = inputChild.props as Record<'id', string | undefined>;
const isInvalid = showMessages && messagesType === 'error';

return (
<Style.FieldContainer>
{!!label && (
Expand All @@ -95,11 +98,16 @@ export const Field: Field = ({

{React.cloneElement(inputChild, {
disabled,
'aria-invalid': isInvalid || undefined,
})}

{!!hintMessage && <Style.HintItem>{hintMessage}</Style.HintItem>}

<VerificationMessages messages={messages} type={messagesType} />
<VerificationMessages
messages={messages}
type={messagesType}
inputId={id}
/>
</Style.InputContainer>
</Style.FieldContainer>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,44 +26,60 @@ exports[`<VerificationMessages /> UI snapshot renders with default props and som
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="error"
>
<strong>
Uh oh!
</strong>
This field is required
<output
role="alert"
>
<strong>
Uh oh!
</strong>
This field is required
</output>
</li>
<li
class="emotion-2 emotion-3"
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="error"
>
<strong>
Uh oh!
</strong>
Must be at least 3 characters
<output
role="alert"
>
<strong>
Uh oh!
</strong>
Must be at least 3 characters
</output>
</li>
<li
class="emotion-2 emotion-3"
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="error"
>
Must contain 1 number
,
Must contain 1 symbol
<output
role="alert"
>
Must contain 1 number
,
Must contain 1 symbol
</output>
</li>
<li
class="emotion-2 emotion-3"
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="error"
>
<strong>
1
</strong>
one
,
<strong>
2
</strong>
two
<output
role="alert"
>
<strong>
1
</strong>
one
,
<strong>
2
</strong>
two
</output>
</li>
</ul>
`;
Expand Down Expand Up @@ -95,10 +111,14 @@ exports[`<VerificationMessages /> UI snapshot renders with non-default props 1`]
style="opacity: 1; max-height: 48px; transition-duration: 350ms; transition-property: max-height, opacity; transition-timing-function: ease-in-out;"
type="success"
>
<strong>
Congrats!
</strong>
Your app was approved
<output
role="alert"
>
<strong>
Congrats!
</strong>
Your app was approved
</output>
</li>
</ul>
`;
6 changes: 5 additions & 1 deletion src/shared-components/verificationMessages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface VerificationMessagesProps {
* Centers the messages
*/
centered?: boolean;
inputId?: string;
/**
* Object of key and React Node message pair. It also accepts an array of React Node as value
*/
Expand All @@ -32,6 +33,7 @@ export interface VerificationMessagesProps {
*/
export const VerificationMessages: React.FC<VerificationMessagesProps> = ({
centered = false,
inputId,
messages = {},
type = 'error',
}) => {
Expand All @@ -54,7 +56,9 @@ export const VerificationMessages: React.FC<VerificationMessagesProps> = ({
.map((key) => (
<HelperTransition key={key}>
<Style.MessageItem type={type}>
{formatMessage(messages[key])}
<output htmlFor={inputId} role="alert">
{formatMessage(messages[key])}
</output>
</Style.MessageItem>
</HelperTransition>
))
Expand Down

0 comments on commit a724a83

Please sign in to comment.