Back to React Spectrum

useBreadcrumbs

packages/react-aria/docs/breadcrumbs/useBreadcrumbs.mdx

2022-12-167.2 KB
Original Source

{/* Copyright 2020 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs'; export default Layout;

import docs from 'docs:@react-aria/breadcrumbs'; import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, PageDescription} from '@react-spectrum/docs'; import {Keyboard} from '@react-spectrum/text'; import packageData from '@react-aria/breadcrumbs/package.json'; import Anatomy from './anatomy.svg';


category: Navigation keywords: [breadcrumbs, aria]

useBreadcrumbs

<PageDescription>{docs.exports.useBreadcrumbs.description}</PageDescription>

<HeaderInfo packageData={packageData} componentNames={['useBreadcrumbs', 'useBreadcrumbItem']} sourceData={[ {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/'} ]} />

API

<FunctionAPI function={docs.exports.useBreadcrumbs} links={docs.links} /> <FunctionAPI function={docs.exports.useBreadcrumbItem} links={docs.links} />

Features

Breadcrumbs provide a list of links to parent pages of the current page in hierarchical order. useBreadcrumbs and useBreadcrumbItem help implement these in an accessible way.

  • Support for mouse, touch, and keyboard interactions on breadcrumbs
  • Support for navigation links via <a> elements or custom element types via ARIA
  • Localized ARIA labeling support for landmark navigation region
  • Support for disabled breadcrumbs

Anatomy

<Anatomy />

Breadcrumbs consist of a navigation landmark element and a list of links, typically with a visual separator icon between each item. The last link represents the current page in the hierarchy, with the previous links representing the parent pages of the current page. Each of these parent links can be clicked, tapped, or triggered via the <Keyboard>Enter</Keyboard> key to navigate to that page.

useBreadcrumbs returns props to be spread onto the navigation element:

<TypeContext.Provider value={docs.links}> <InterfaceType properties={docs.links[docs.exports.useBreadcrumbs.return.id].properties} /> </TypeContext.Provider>

useBreadcrumbItem returns props to spread onto the individual breadcrumb links:

<TypeContext.Provider value={docs.links}> <InterfaceType properties={docs.links[docs.exports.useBreadcrumbItem.return.id].properties} /> </TypeContext.Provider>

Example

This example displays a basic list of breadcrumbs using an HTML <nav> element, and a <ol> for the list of links. Each link is a span because we are handling the interactions locally via onPress. useBreadcrumbItem automatically handles exposing these spans as links to assistive technology.

The chevrons between each link are rendered using a span with aria-hidden="true" so that screen readers do not pick them up. You could also render them similarly using SVG icons, CSS :after, or other techniques.

The last link is non-interactive since it represents the current page. This is passed to the last breadcrumb item by cloning the element and adding the isCurrent prop.

tsx
import {useBreadcrumbs, useBreadcrumbItem} from '@react-aria/breadcrumbs';

function Breadcrumbs(props) {
  let {navProps} = useBreadcrumbs(props);
  let childCount = React.Children.count(props.children);

  return (
    <nav {...navProps}>
      <ol style={{display: 'flex', listStyle: 'none', margin: 0, padding: 0}}>
        {React.Children.map(props.children, (child, i) =>
          React.cloneElement(child, {isCurrent: i === childCount - 1})
        )}
      </ol>
    </nav>
  )
}

function BreadcrumbItem(props) {
  let ref = React.useRef(null);
  let {itemProps} = useBreadcrumbItem({...props, elementType: 'span'}, ref);
  return (
    <li>
      <span
        {...itemProps}
        ref={ref}
        style={{
          color: props.isDisabled ? 'var(--gray)' : 'var(--blue)',
          textDecoration: props.isCurrent || props.isDisabled ? 'none' : 'underline',
          fontWeight: props.isCurrent ? 'bold' : null,
          cursor: props.isCurrent || props.isDisabled ? 'default' : 'pointer'
        }}>
        {props.children}
      </span>
      {!props.isCurrent &&
        <span aria-hidden="true" style={{padding: '0 5px'}}>{'›'}</span>
      }
    </li>
  );
}

<Breadcrumbs>
  <BreadcrumbItem onPress={() => alert('Pressed Folder 1')}>Folder 1</BreadcrumbItem>
  <BreadcrumbItem onPress={() => alert('Pressed Folder 2')}>Folder 2</BreadcrumbItem>
  <BreadcrumbItem>Folder 3</BreadcrumbItem>
</Breadcrumbs>

To render breadcrumbs that navigate to other pages rather than handle events via onPress, use an <a> element for each BreadcrumbItem. This is the default elementType, so the option can be omitted from useBreadcrumbItem.

tsx
///- begin collapse -///
function Breadcrumbs(props) {
  let {navProps} = useBreadcrumbs(props);
  let childCount = React.Children.count(props.children);

  return (
    <nav {...navProps}>
      <ol style={{display: 'flex', listStyle: 'none', margin: 0, padding: 0}}>
        {React.Children.map(props.children, (child, i) =>
          React.cloneElement(child, {isCurrent: i === childCount - 1})
        )}
      </ol>
    </nav>
  );
}
///- end collapse -///
function BreadcrumbItem(props) {
  let ref = React.useRef(null);
  let {itemProps} = useBreadcrumbItem(props, ref);
  return (
    <li>
      <a
        {...itemProps}
        ref={ref}
        href={props.href}
        style={{
          color: props.isDisabled ? 'var(--gray)' : 'var(--blue)',
          textDecoration: props.isCurrent || props.isDisabled ? 'none' : 'underline',
          fontWeight: props.isCurrent ? 'bold' : null,
          cursor: props.isCurrent || props.isDisabled ? 'default' : 'pointer'
        }}>
        {props.children}
      </a>
      {!props.isCurrent &&
        <span aria-hidden="true" style={{padding: '0 5px'}}>{'›'}</span>
      }
    </li>
  );
}

<Breadcrumbs>
  <BreadcrumbItem href="#">Home</BreadcrumbItem>
  <BreadcrumbItem href="#">React Aria</BreadcrumbItem>
  <BreadcrumbItem>useBreadcrumbs</BreadcrumbItem>
</Breadcrumbs>

Usage

The following examples show how to use the Breadcrumbs component created in the above examples.

Disabled

Breadcrumbs can be disabled using the isDisabled prop, passed to each disabled BreadcrumbItem. This indicates that navigation is not currently available. When a breadcrumb is disabled, onPress will not be triggered, navigation will not occur, and links will be marked as aria-disabled for assistive technologies.

tsx
<Breadcrumbs>
  <BreadcrumbItem href="#" isDisabled>Home</BreadcrumbItem>
  <BreadcrumbItem href="#">React Aria</BreadcrumbItem>
  <BreadcrumbItem>useBreadcrumbs</BreadcrumbItem>
</Breadcrumbs>