Improve accessibility (#1956)

Fixes several accessibility issues:

- Provide a style for empty table column headers
- Add aria references and aria-labels
- Remove aria references if the referenced element is not rendered
This commit is contained in:
Matthias Thieroff
2022-02-17 14:00:16 +01:00
committed by GitHub
parent 9fa0396167
commit 1fe7b0a01e
12 changed files with 61 additions and 33 deletions

View File

@@ -37,6 +37,7 @@ type Props = {
label?: string;
testId?: string;
searchPlaceholder?: string;
groupAriaLabelledby?: string;
};
const createAbsoluteLink = (url: string) => {
@@ -52,7 +53,8 @@ const OverviewPageActions: FC<Props> = ({
groupSelected,
label,
testId,
searchPlaceholder
searchPlaceholder,
groupAriaLabelledby
}) => {
const history = useHistory();
const location = useLocation();
@@ -62,6 +64,7 @@ const OverviewPageActions: FC<Props> = ({
const groupSelector = groups && (
<div className="column is-flex">
<Select
ariaLabelledby={groupAriaLabelledby}
className="is-fullwidth"
options={groups.map(g => ({ value: g, label: g }))}
value={currentGroup}

View File

@@ -24,6 +24,7 @@
import React, { FC } from "react";
import classNames from "classnames";
import { Color, Size } from "./styleConstants";
import { useTranslation } from "react-i18next";
type Props = {
className?: string;
@@ -51,8 +52,10 @@ const Tag: FC<Props> = ({
title,
onClick,
onRemove,
children,
children
}) => {
const [t] = useTranslation("commons");
let showIcon = null;
if (icon) {
showIcon = (
@@ -64,7 +67,7 @@ const Tag: FC<Props> = ({
}
let showDelete = null;
if (onRemove) {
showDelete = <button className="tag is-delete" onClick={onRemove} />;
showDelete = <button className="tag is-delete" onClick={onRemove} aria-label={t("tag.delete")} />;
}
return (
@@ -78,7 +81,7 @@ const Tag: FC<Props> = ({
{
"is-outlined": outlined,
"is-rounded": rounded,
"is-clickable": onClick,
"is-clickable": onClick
},
size === "small" && smallClassNames
)}

View File

@@ -34,6 +34,7 @@ exports[`Storyshots BranchSelector Default 1`] = `
className="control select is-fullwidth"
>
<select
aria-labelledby="branch-select_0"
disabled={false}
onBlur={[Function]}
onChange={[Function]}
@@ -3048,7 +3049,6 @@ exports[`Storyshots Forms/Radio Default 1`] = `
className="radio mr-2"
>
<input
aria-describedby="radio_56"
aria-labelledby="radio_55"
checked={false}
onBlur={[Function]}
@@ -3070,7 +3070,6 @@ exports[`Storyshots Forms/Radio Default 1`] = `
className="radio mr-2"
>
<input
aria-describedby="radio_58"
aria-labelledby="radio_57"
checked={true}
onBlur={[Function]}
@@ -3100,7 +3099,6 @@ exports[`Storyshots Forms/Radio Disabled 1`] = `
disabled={true}
>
<input
aria-describedby="radio_60"
aria-labelledby="radio_59"
checked={true}
disabled={true}
@@ -3128,7 +3126,6 @@ Array [
className="radio mr-2"
>
<input
aria-describedby="radio_68"
aria-labelledby="radio_67"
checked={false}
onBlur={[Function]}
@@ -3160,7 +3157,6 @@ exports[`Storyshots Forms/Radio ReactHookForm 1`] = `
className="radio mr-2"
>
<input
aria-describedby="radio_70"
aria-labelledby="radio_69"
defaultChecked={true}
name="rememberMe"
@@ -3184,7 +3180,6 @@ exports[`Storyshots Forms/Radio ReactHookForm 1`] = `
className="radio mr-2"
>
<input
aria-describedby="radio_72"
aria-labelledby="radio_71"
name="rememberMe"
onBlur={[Function]}
@@ -3208,7 +3203,6 @@ exports[`Storyshots Forms/Radio ReactHookForm 1`] = `
className="radio mr-2 ml-2"
>
<input
aria-describedby="radio_74"
aria-labelledby="radio_73"
name="scramblePassword"
onBlur={[Function]}
@@ -3232,7 +3226,6 @@ exports[`Storyshots Forms/Radio ReactHookForm 1`] = `
disabled={true}
>
<input
aria-describedby="radio_76"
aria-labelledby="radio_75"
disabled={true}
name="disabled"
@@ -3256,7 +3249,6 @@ exports[`Storyshots Forms/Radio ReactHookForm 1`] = `
className="radio mr-2"
>
<input
aria-describedby="radio_78"
aria-labelledby="radio_77"
name="readonly"
onBlur={[Function]}
@@ -3298,7 +3290,6 @@ Array [
className="radio mr-2"
>
<input
aria-describedby="radio_66"
aria-labelledby="radio_65"
checked={false}
onBlur={[Function]}

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React, { ChangeEvent, FC, FocusEvent } from "react";
import React, { ChangeEvent, FC, FocusEvent, useMemo } from "react";
import classNames from "classnames";
import { Help } from "../index";
import { createFormFieldWrapper, FieldProps, FieldType, isLegacy, isUsingRef } from "./FormFieldTypes";
@@ -47,8 +47,8 @@ const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({
ariaLabelledby,
...props
}) => {
const id = ariaLabelledby || createA11yId("radio");
const helpId = createA11yId("radio");
const id = useMemo(() => ariaLabelledby || createA11yId("radio"), [ariaLabelledby]);
const helpId = useMemo(() => createA11yId("radio"), []);
const renderHelp = () => {
const helpText = props.helpText;
@@ -77,7 +77,7 @@ const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({
}
};
const labelElement = props.label ? (<span id={id}>{props.label}</span>) : null;
const labelElement = props.label ? <span id={id}>{props.label}</span> : null;
return (
<fieldset className="is-inline-block" disabled={readOnly}>
@@ -98,7 +98,7 @@ const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({
ref={props.innerRef}
defaultChecked={defaultChecked}
aria-labelledby={id}
aria-describedby={helpId}
aria-describedby={props.helpText ? helpId : undefined}
/>{" "}
{labelElement}
{renderHelp()}

View File

@@ -124,7 +124,7 @@ const InnerSelect: FC<FieldProps<BaseProps, HTMLSelectElement, string>> = ({
onChange={handleInput}
onBlur={handleBlur}
disabled={disabled}
aria-labelledby={label ? a11yId : undefined}
aria-labelledby={ariaLabelledby || (label ? a11yId : undefined)}
aria-describedby={helpText ? helpId : undefined}
{...createAttributesForTesting(testId)}
>