Accessibility: Default Icon to aria-hidden (#84362)

* Icon: aria hide icon, unless a label is set

* Update doc

* Remove weird auto import

* Fix fialing tests

* Add recommendation for Tooltip

* Consider more aria attributes to support Tooltip

* Handle tabIndex and aria-hidden case

* Add comment about aria-label
This commit is contained in:
Tobias Skarhed 2024-04-04 12:07:50 +02:00 committed by GitHub
parent 01afca9d99
commit f387cff836
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 26 additions and 2 deletions

View File

@ -7,6 +7,14 @@ import { Icon } from './Icon';
Grafana's wrapper component over [Font Awesome](https://fontawesome.com/) and Unicons icons Grafana's wrapper component over [Font Awesome](https://fontawesome.com/) and Unicons icons
## Accessibility
`Icon` is aria-hidden by default. If your icon has semantic meaning, please provide a `title` or wrap it in a `Tooltip`.
### Usage with Tooltip
If you decide to use a `Tooltip` to wrap `Icon`, you need to set a `title` or `aria-label` on the `Icon` component in order for it to appear in the accessibility tree. `Tooltip` only provides `aria-describedby` on interaction.
### Changing icon size ### Changing icon size
By default `Icon` has width and height of `16px` and font-size of `14px`. Pass `className` to control icon's size: By default `Icon` has width and height of `16px` and font-size of `14px`. Pass `className` to control icon's size:

View File

@ -13,6 +13,9 @@ export interface IconProps extends Omit<React.SVGProps<SVGElement>, 'onLoad' | '
name: IconName; name: IconName;
size?: IconSize; size?: IconSize;
type?: IconType; type?: IconType;
/**
* Give your icon a semantic meaning. The icon will be hidden from screen readers, unless this prop or an aria-label is provided.
*/
title?: string; title?: string;
} }
@ -60,6 +63,13 @@ export const Icon = React.forwardRef<SVGElement, IconProps>(
return ( return (
<SVG <SVG
aria-hidden={
rest.tabIndex === undefined &&
!title &&
!rest['aria-label'] &&
!rest['aria-labelledby'] &&
!rest['aria-describedby']
}
innerRef={ref} innerRef={ref}
src={svgPath} src={svgPath}
width={svgWid} width={svgWid}

View File

@ -162,7 +162,12 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
</div> </div>
} }
> >
<Icon id="data-source-picker-inline-help" name="info-circle" size="sm" /> <Icon
id="data-source-picker-inline-help"
name="info-circle"
size="sm"
title="Search by data sources help"
/>
</Tooltip> </Tooltip>
</Stack> </Stack>
</Label> </Label>
@ -232,7 +237,7 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
<Stack gap={0.5}> <Stack gap={0.5}>
<span>Search</span> <span>Search</span>
<HoverCard content={<SearchQueryHelp />}> <HoverCard content={<SearchQueryHelp />}>
<Icon name="info-circle" size="sm" tabIndex={0} /> <Icon name="info-circle" size="sm" tabIndex={0} title="Search help" />
</HoverCard> </HoverCard>
</Stack> </Stack>
</Label> </Label>

View File

@ -91,6 +91,7 @@ exports[`VariableQueryEditor renders correctly 1`] = `
className="css-zyjsuv-input-suffix" className="css-zyjsuv-input-suffix"
> >
<svg <svg
aria-hidden={true}
className="css-1d3xu67-Icon" className="css-1d3xu67-Icon"
height={16} height={16}
id="public/img/icons/unicons/angle-down.svg" id="public/img/icons/unicons/angle-down.svg"