terra-core
terra-core copied to clipboard
terra-icon UX Audit
terra-icon
Known Aliases
Document any known aliases of the component, decide if another name makes more sense.
- [ ] Has known aliases
- [ ] Requires name change
Design Standard Doc
Any documentation needed to be added to terra-ui describing the make up and usage of the component Any doc examples that need to be updated?
- [ ] Missing design standard documentation linkage.
Guides
Any guides needed to be added to terra-ui describing the usage of this component when used with other components.
- [X] Missing Guides
- Guides on how teams can customize the color
- [ ] Missing UX recommended Usage.
- [ ] Deprecation guide
Accessibility Guides
- [X] Missing Accessibility Guides
- Need to make sure that icons are not used directly in an interactable way. If so, use button, for example, instead.
Behaviours
- [X] Missing behaviours
- Evaluate the API to see if we can somehow invert the aria label prop.
- Add title and it should match the aria label (potentially the svg title)
- Have human readable titles/aliases as part of the OCS repo but have option for consumers to specify as well
- Possibly look to characterize "themeable" icons differently (e.g. customizable)
- [ ] Contains bad practice behaviours that should be removed
Accessibility
- [ ] Meets wcag 2.0/section 508 standards
- [ ] Meets wcag 2.1/en 301 549 standards
Deprecation
- [ ] Component is a bad pattern and should be deprecated.
Related Issues
Other Considerations
Possibly some general clean up of the OCS icon repository. Need to evaluate icons to make sure they are low lighting correctly. Look into exporting at 16 rather than 64. Need to evaluate styling for stand-alone use (without extra styling for text alignment)
Additional Consideration:
Need to evaluate further if icons need the ability to be provided as isIconOnly
or isStandalone
with the additional vertical positioning styles removed that make icons look correctly aligned with text, for use in locations where vertical and horizontal centering is critical and icons are all by themselves (e.g. terra-button which is isIconOnly
).
Concerns: One of the largest concerns from a UX perspective is not all icons are going to be approved for standalone use (no text or labels beside them) based on Humans Factors recommendations and Design Standards, only certain icons that have wide/broad understanding can be used by themselves, so having a universal prop that indicates all can be used as standalone might violate Design Standards. We'll need to evaluate further how best to approach it.
Tech Design 1
Overview
According to https://a11y-101.com/development/svg , the simplest way to make svgs accessible is to use them in an img
tag if they are meaningful. An img
tag supports the alt property for screenreaders.
Currently, terra-icon works as follows:
attributes = {
"viewBox":"0 0 48 48",
"xmlns":"http://www.w3.org/2000/svg",
"data-name":"Layer 1"
};
<IconBase {...attributes}>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</IconBase>
Which returns the following html
:
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
data-name="Layer 1"
>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</svg>
In order to meet accessibility standards, the resulting html
should be a img
tag. Since img
and svg
have different attributes (e.g. img
does not support child nodes), this will change the props for IconBase
, resulting in an active change for this story.
Current Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
ariaLabel | string | optional | null | String that labels the current element. If aria-label is present, role is site to img and aria-hidden is removed |
children | node | optional | null | Child nodes |
isBidi | bool | optional | false | Should the svg mirror when dir=”rtl” |
isSpin | bool | optional | false | Should the svg spin |
height | string | optional | 1em | Height of SVG |
width | string | optional | 1em | Width of SVG |
focusable | string | optional | false | Focusable attribute |
Proposed Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
alt | string | required | "" | String that labels the current element. If aria-label is present, role is site to img and aria-hidden is removed |
svgSource | string | required | null | Svg input for the icon. Can be inline svg or a file |
imageType | enum | optional | “informative” | Type of icon. Currently supports "decorative" and "infomative" |
encoding | enum | optional | "none" | “none”: svg file , “utf8”: inline svg as Unicode, “base64": inline svg as base64 |
isBidi | bool | optional | false | Should the svg mirror when dir=”rtl” |
isSpin | bool | optional | false | Should the svg spin |
height | string | optional | 1em | Height of SVG |
width | string | optional | 1em | Width of SVG |
focusable | string | optional | false | Focusable attribute |
This is an active change resulting in a major version bump. children
and ariaLabel
will be removed in the next major version.
Examples uses
- When
encoding
is set to"none"
.
const attributes = {
isBidi: false,
iconType: "informative",
alt: "plus icon",
encoding: "none" //default value,
svgSource: "path/to/file.svg"
};
return ( <img src={svgSource} {... other attributes} ></img> );
- When
encoding
is set to"utf8"
.
const attributes = {
isBidi: false,
iconType: "informative",
alt: "plus icon",
encoding: "utf8"
svgSource: `<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z"/></svg>`,
};
const generatedSVGSource = `data:image/svg+xml;${encoding},${svgSource}`;
return ( <img src={generatedSVGSource} {...other attributes}></img> );
- When
encoding
is set to"base64"
.
const attributes = {
isBidi: false,
iconType: "informative",
alt: "plus icon",
encoding: "base64"
svgSource: `PHN2ZyBkYXRhLW5hbWU9IkxheWVyIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQ4IDQ4Ij48cGF0aCBkPSJNNDggMjFIMjdWMGgtNnYyMUgwdjZoMjF2MjFoNlYyN2gyMXoiLz48L3N2Zz4=`,
};
const generatedSVGSource = `data:image/svg+xml;${encoding},${svgSource}`;
return ( <img src={generatedSVGSource} {...other attributes}></img> );
Accessibility
In order to meet accessibility standards, the imageType
prop will be used to set the type of the icon as "informative"
or "decorative"
which will set the attributes of the img
so that it will be read/ignored by screenreaders.
if imageType="decorative"
:
attributes.role = presentation
otherwise
attributes.role = undefined
To Do
- Perform testing to find out which attributes would be added to the
img
tag orsvg
tag.
As Tech Design 1 is causing complications with the existing icon coloring logic, it is being dropped for Tech Design 2.
Tech Design 2
Overview
According to https://www.deque.com/blog/creating-accessible-svgs/ , the simplest and reccommended way to make svgs accessible is to use them in an img
tag if they are meaningful. An img
tag supports the alt property for screenreaders. However, terra-icon is deigned so that consumers can change the color of non-static icons by simply using the font-color. In order to maintain this feature, deque's alternative recommendation which is to add a title
tag to a svg
will be used.
Currently, terra-icon works as follows:
attributes = {
"viewBox":"0 0 48 48",
"xmlns":"http://www.w3.org/2000/svg",
"data-name":"Layer 1"
};
<IconBase {...attributes}>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</IconBase>
Which returns the following html
:
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
data-name="Layer 1"
>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</svg>
In order to meet accessibility standards, the resulting svg
should have a title
tag like the following:
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
data-name="Layer 1"
>
<title>icon title</title>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</svg>
Solution
The default component will be updated to be meaningful
. This is so that consumers will adher to accessibility standards by default. A sub-component IconDecorative
will be added for consumers to utilize decorative icons.
Default Meaningful Component
The props for the component will be updated as follows:
Current Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
ariaLabel | string | optional | null | String that labels the current element; If aria-label is present, role is site to img and aria-hidden is removed |
children | node | optional | null | Child nodes |
isBidi | bool | optional | false | Should the svg mirror when dir=”rtl” |
isSpin | bool | optional | false | Should the svg spin |
height | string | optional | 1em | Height of SVG |
width | string | optional | 1em | Width of SVG |
focusable | string | optional | false | Focusable attribute |
Proposed Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
a11yLabel | string | required | - | String that labels the current element |
children | node | optional | null | Child nodes |
isBidi | bool | optional | false | Should the svg mirror when dir=”rtl” |
isSpin | bool | optional | false | Should the svg spin |
height | string | optional | 1em | Height of SVG |
width | string | optional | 1em | Width of SVG |
focusable | string | optional | false | Focusable attribute |
This is an active change resulting in a major version bump. children
and ariaLabel
will be removed in the next major version.
Resulting html
the default iconBase
will return the following html
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
data-name="Layer 1"
>
<title>icon title</title>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</svg>
Decorative icon
For a decorative icon, the role
is set to presentation
with no title prop.
Proposed Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
children | node | optional | null | Child nodes |
isBidi | bool | optional | false | Should the svg mirror when dir=”rtl” |
isSpin | bool | optional | false | Should the svg spin |
height | string | optional | 1em | Height of SVG |
width | string | optional | 1em | Width of SVG |
focusable | string | optional | false | Focusable attribute |
Resulting html
<svg
viewBox="0 0 48 48"
xmlns="http://www.w3.org/2000/svg"
data-name="Layer 1"
role="presentation"
>
<path d="M48 21H27V0h-6v21H0v6h21v21h6V27h21z" ></path>
</svg>