question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Breadcrumb] Visual separators included in list item count for screen reader

See original GitHub issue

The accessibility section at the bottom of this link: https://material-ui.com/components/breadcrumbs/ indicates the use of ‘aria-hidden’ to prevent screen reader announcement of the visual separators between links.

When using ChromeVox, the separators are not read out, however, the separators are included in the item count of the ordered list, providing misleading information to the user.

  • [ x] The issue is present in the latest release.
  • [ x] I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

Sample breadcrumbs:

Home / About Us / Contact

Screen reader reads:

tab -> ‘ordered list with 5 items, Home link list item’ tab -> ‘About Us, link list item’ tab -> ‘Contact, link list item’

  • includes separators in list item count

Expected Behavior 🤔

Sample breadcrumbs:

Home / About Us / Contact

Screen reader reads:

tab -> ‘ordered list with 3 items, Home link list item’ tab -> ‘About Us, link list item’ tab -> ‘Contact, link list item’

  • should not include separators in list item count
  • screen reader should read out that it is an ordered list with 3 items

Steps to Reproduce 🕹

Visit https://material-ui.com/components/breadcrumbs/ Steps:

  1. Turn on screen reader
  2. Tab to breadcrumb demo
  3. Listen to screen reader read out number of items in list

Environment 🌎

| Material-UI/core | 4.9.8 | | React | 16.8.6 | | Chrome | 83.0.4103.116 | | ChromeVox Classic Extension | 53.0.2784.6 |

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
mbrookescommented, Jun 27, 2020
--- a/packages/material-ui/src/Breadcrumbs/BreadcrumbCollapsed.js
+++ b/packages/material-ui/src/Breadcrumbs/BreadcrumbCollapsed.js
@@ -8,6 +8,9 @@ import ButtonBase from '../ButtonBase';
 const styles = (theme) => ({
   root: {
     display: 'flex',
+  },
+  buttonBase: {
+    display: 'flex',
     marginLeft: theme.spacing(0.5),
     marginRight: theme.spacing(0.5),
     backgroundColor: theme.palette.grey[100],
@@ -26,18 +29,30 @@ const styles = (theme) => ({
     width: 24,
     height: 16,
   },
+  /* Styles applied to the separator element. */
+  separator: {
+    display: 'flex',
+    userSelect: 'none',
+    marginLeft: 8,
+    marginRight: 8,
+  },
 });
 
 /**
  * @ignore - internal component.
  */
 function BreadcrumbCollapsed(props) {
-  const { classes, ...other } = props;
+  const { classes, separator, ...other } = props;
 
   return (
-    <ButtonBase component="li" className={classes.root} focusRipple {...other}>
-      <MoreHorizIcon className={classes.icon} />
-    </ButtonBase>
+    <li className={classes.root} {...other}>
+      <ButtonBase className={classes.buttonBase} focusRipple>
+        <MoreHorizIcon className={classes.icon} />
+      </ButtonBase>
+      <span className={classes.separator} aria-hidden="true">
+        {separator}
+      </span>
+    </li>
   );
 }
 
@@ -46,6 +61,10 @@ BreadcrumbCollapsed.propTypes = {
    * @ignore
    */
   classes: PropTypes.object.isRequired,
+  /**
+   * Separator node.
+   */
+  separator: PropTypes.node,
 };
 
 export default withStyles(styles, { name: 'PrivateBreadcrumbCollapsed' })(BreadcrumbCollapsed);
diff --git a/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js b/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
index 41189fb89..a150b8d6b 100644
--- a/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
+++ b/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
@@ -19,7 +19,9 @@ export const styles = {
     listStyle: 'none',
   },
   /* Styles applied to the li element. */
-  li: {},
+  li: {
+    display: 'flex',
+  },
   /* Styles applied to the separator element. */
   separator: {
     display: 'flex',
@@ -29,23 +31,6 @@ export const styles = {
   },
 };
 
-function insertSeparators(items, className, separator) {
-  return items.reduce((acc, current, index) => {
-    if (index < items.length - 1) {
-      acc = acc.concat(
-        current,
-        <li aria-hidden key={`separator-${index}`} className={className}>
-          {separator}
-        </li>,
-      );
-    } else {
-      acc.push(current);
-    }
-
-    return acc;
-  }, []);
-}
-
 const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
   const {
     children,
@@ -90,7 +75,12 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
 
     return [
       ...allItems.slice(0, itemsBeforeCollapse),
-      <BreadcrumbCollapsed aria-label={expandText} key="ellipsis" onClick={handleClickExpand} />,
+      <BreadcrumbCollapsed
+        separator={separator}
+        aria-label={expandText}
+        key="ellipsis"
+        onClick={handleClickExpand}
+      />,
       ...allItems.slice(allItems.length - itemsAfterCollapse, allItems.length),
     ];
   };
@@ -113,6 +103,11 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
     .map((child, index) => (
       <li className={classes.li} key={`child-${index}`}>
         {child}
+        {index < children.length - 1 && (
+          <span className={classes.separator} aria-hidden="true">
+            {separator}
+          </span>
+        )}
       </li>
     ));
 
@@ -125,13 +120,9 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
       {...other}
     >
       <ol className={classes.ol}>
-        {insertSeparators(
-          expanded || (maxItems && allItems.length <= maxItems)
-            ? allItems
-            : renderItemsBeforeAndAfter(allItems),
-          classes.separator,
-          separator,
-        )}
+        {expanded || (maxItems && allItems.length <= maxItems)
+          ? allItems
+          : renderItemsBeforeAndAfter(allItems)}
       </ol>
     </Typography>
   );
Read more comments on GitHub >

github_iconTop Results From Across the Web

[Breadcrumb] Visual separators included in list item count for ...
Steps: Turn on screen reader; Tab to breadcrumb demo; Listen to screen reader read out number of items in list. Environment.
Read more >
Accessible Breadcrumb Navigation Pattern - GitHub Pages
Screen Reader Announcements? You may notice that the dividers between each link/list item of the breadcrumb are created via CSS pseudo elements ......
Read more >
Breadcrumb Example | APG | WAI - W3C
The separators are part of the visual presentation that signifies the breadcrumb trail, which is already semantically represented by the nav element with...
Read more >
Accessible Breadcrumbs - example and best practices - Aditus
When using markup for the breadcrumb's separator, it's important to make it a decorative element, so that screen reader users don't announce it...
Read more >
Breadcrumb · Bootstrap v5.0
Use an ordered or unordered list with linked list items to create a minimally styled breadcrumb. Use our utilities to add additional styles...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found