diff --git a/CHANGELOG.md b/CHANGELOG.md index fafc44d507f..8a16af93b8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ - Added `disabled` prop to the `EuiCheckboxGroup` definition ([#2545](https://github.com/elastic/eui/pull/2545)) - Added `disabled` option to the `option` attribute of the `options` object that is passed to the `EuiCheckboxGroup` so that checkboxes in a group can be individually disabled ([#2548](https://github.com/elastic/eui/pull/2548)) - Added `EuiAspectRatio` component that allows for responsively resizing embeds ([#2535](https://github.com/elastic/eui/pull/2535)) +- Fixed `EuiIcon` accessibility by adding a `title` prop and a default `aria-label` ([#2554](https://github.com/elastic/eui/pull/2554)) - Added `display` and `titleSize` props to `EuiCard` ([#2566](https://github.com/elastic/eui/pull/2566)) - Added `accessibility` glyph to `EuiIcon` ([#2566](https://github.com/elastic/eui/pull/2566)) diff --git a/scripts/compile-icons.js b/scripts/compile-icons.js index e4f1cd04555..98516bbd745 100644 --- a/scripts/compile-icons.js +++ b/scripts/compile-icons.js @@ -8,28 +8,12 @@ const srcDir = path.resolve(rootDir, 'src'); const iconsDir = path.resolve(srcDir, 'components', 'icon', 'assets'); function pascalCase(x) { - return x.replace(/^(.)|[^a-zA-Z]([a-zA-Z])/g, (match, char1, char2) => (char1 || char2).toUpperCase()); + return x.replace(/^(.)|[^a-zA-Z]([a-zA-Z])/g, (match, char1, char2) => + (char1 || char2).toUpperCase() + ); } -const iconFiles = glob.sync( - '**/*.svg', - { cwd: iconsDir, realpath: true } -); - -function defaultTemplate({ - template - }, opts, { - imports, - componentName, - props, - jsx, - exports - }) { - return template.ast`${imports} -const ${componentName} = (${props}) => ${jsx} -${exports} -`; -} +const iconFiles = glob.sync('**/*.svg', { cwd: iconsDir, realpath: true }); iconFiles.forEach(async filePath => { const svgSource = fs.readFileSync(filePath); @@ -40,7 +24,7 @@ iconFiles.forEach(async filePath => { throw new Error(`${filePath} is missing a 'viewBox' attribute`); } - const jsxSource = (await svgr( + const jsxSource = await svgr( svgSource, { plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'], @@ -52,18 +36,23 @@ iconFiles.forEach(async filePath => { ], }, svgProps: { - xmlns: 'http://www.w3.org/2000/svg' + xmlns: 'http://www.w3.org/2000/svg', }, - template: ({ template }, opts, { imports, componentName, props, jsx }) => template.ast` + titleProp: true, + template: ( + { template }, + opts, + { imports, componentName, props, jsx } + ) => template.ast` ${imports} const ${componentName} = (${props}) => ${jsx} export const icon = ${componentName}; - ` + `, }, { - componentName: `EuiIcon${pascalCase(path.basename(filePath, '.svg'))}` + componentName: `EuiIcon${pascalCase(path.basename(filePath, '.svg'))}`, } - )); + ); const outputFilePath = filePath.replace(/\.svg$/, '.js'); fs.writeFileSync(outputFilePath, jsxSource); diff --git a/src-docs/src/views/icon/accessibility.js b/src-docs/src/views/icon/accessibility.js index 8b5cadf5999..2152cd19d90 100644 --- a/src-docs/src/views/icon/accessibility.js +++ b/src-docs/src/views/icon/accessibility.js @@ -4,6 +4,6 @@ import { EuiIcon } from '../../../../src/components'; export default () => (
- +
); diff --git a/src-docs/src/views/icon/icon_example.js b/src-docs/src/views/icon/icon_example.js index f9bcb75ef78..8d1aee965ce 100644 --- a/src-docs/src/views/icon/icon_example.js +++ b/src-docs/src/views/icon/icon_example.js @@ -11,6 +11,7 @@ import { EuiLink, EuiText, EuiSpacer, + EuiCallOut, } from '../../../../src/components'; const iconHtmlWarning = () => ( @@ -87,7 +88,7 @@ const iconTypesSource = require('!!raw-loader!./icon_types'); const iconTypesSnippet = [ '', '', - '', + '', 'Works in other components too', ]; @@ -109,6 +110,20 @@ export const IconExample = {

+ + For better accessibility it's always recommended to give a + descriptive title based on the icon use. + + } + color="warning"> +

+ If the icon is purely decorative, pass{' '} + aria-hidden=true. +

+
+ ), sections: [ @@ -152,8 +167,8 @@ export const IconExample = { ], text: (

- Editor icons relate to the visual styling of elements and are - commonly used within EuiButtonGroup components. + Editor icons relate to the visual styling of elements and are commonly + used within EuiButtonGroup components.

), snippet: editorSnippet, @@ -331,26 +346,6 @@ export const IconExample = { snippet: iconColorsSnippet, demo: , }, - { - title: 'Accessibility', - source: [ - { - type: GuideSectionTypes.JS, - code: accessibilitySource, - }, - { - type: GuideSectionTypes.HTML, - code: iconsHtml, - }, - ], - text: ( -

- You can title the SVG by passing the aria-label{' '} - prop to EuiIcon. No value is set by default. -

- ), - demo: , - }, { title: 'Custom SVGs', text: ( diff --git a/src-docs/src/views/icon/icon_types.js b/src-docs/src/views/icon/icon_types.js index 33894eb9f3d..afb531afd67 100644 --- a/src-docs/src/views/icon/icon_types.js +++ b/src-docs/src/views/icon/icon_types.js @@ -30,6 +30,7 @@ export default () => (

http://some.svg

@@ -59,7 +60,9 @@ export default () => ( - + http://some.svg diff --git a/src/components/accordion/__snapshots__/accordion.test.tsx.snap b/src/components/accordion/__snapshots__/accordion.test.tsx.snap index d5bf8e4975e..311e985c2a7 100644 --- a/src/components/accordion/__snapshots__/accordion.test.tsx.snap +++ b/src/components/accordion/__snapshots__/accordion.test.tsx.snap @@ -28,14 +28,21 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = ` type="arrowRight" > { ); } else { const Svg = icon; + + // If it's an empty icon it gets aria-hidden true + const hideIconEmpty = icon === empty && { 'aria-hidden': true }; + + let ariaLabel: any; + + // If no aria-label or aria-labelledby is provided the title will be default + + if (!this.props['aria-label'] && !this.props['aria-labelledby']) { + ariaLabel = { 'aria-label': titleDisplayed }; + } + return ( ); } diff --git a/src/components/image/__snapshots__/image.test.tsx.snap b/src/components/image/__snapshots__/image.test.tsx.snap index 613292b41ef..ceabd9d27c8 100644 --- a/src/components/image/__snapshots__/image.test.tsx.snap +++ b/src/components/image/__snapshots__/image.test.tsx.snap @@ -33,9 +33,12 @@ exports[`EuiImage is rendered and allows full screen 1`] = ` src="/cat.jpg" />