Breadcrumbs

Breadcrumbs are a secondary form of navigation that allow users to keep track and maintain awareness of their location as they move through different pages, folders, or files.

GitHubStorybook
yarn add @workday/canvas-kit-react
Sources
GitHubStorybook
Install
yarn add @workday/canvas-kit-react

Anatomy

Image of a Breadcrumbs with annotation markers.

  1. Root Page: The root page grounds the trail as users navigate to subsequent pages.
  2. Breadcrumb Pages: Each page has its own label. Pages are styled as Hyperlink Text and should be prepended by the word ‘Page’, ie: Page (#).
  3. Current Page/Folder: All users should be aware of which page they are currently viewing. It is not clickable.
  4. Divider: The divider inherits the styling of our Icon Only Tertiary Button Variant, but it is not clickable. Use the Chevron System Icon.
  5. Truncated Breadcrumbs: The Breadcrumb trail will truncate after the Breadcrumb hits a certain width. Truncated pages hide within an Icon Only Tertiary Button Variant styled with a Related Actions System Icon. It should be clear to a screen reader user that there are additional pages that are truncated.
  6. Menu: This is the container that houses truncated pages. Use our Menu component. Screen reader users should be able to navigate through and select a page within the menu.

Usage Guidance

  • Breadcrumbs help to orient the user and keep track of their location as they navigate through a site’s information hierarchy.
  • The component should be used to supplement the primary or main navigation - not replace them.
  • Breadcrumb trails always start with a root page that subsequent pages trace back to.
  • Using Breadcrumbs should enable users to backtrack and jump to previous pages with ease.

Placement

  • Breadcrumbs are represented as a trail of links anchored at the top left of a page, above the page title but below the header.
  • The position of Breadcrumbs should not move as the user navigates through different pages.

Truncation

  • Although truncation behavior is built into the component, be thoughtful about the width of each page title and how to collapse and truncate page items.
  • Page titles and items will truncate after hitting a specified width (all items are set to truncate at 350px, but can be customized).
  • If truncation is required, truncated items will collapse into an Icon Only Tertiary Button Variant, placed in-between the first item (root page) and last item (current page).
  • Users can access truncated pages by clicking into the collapsible Icon Only Tertiary Button Variant and selecting the desired page within the Menu.

Responsive Behavior

  • On responsive or smaller screens, leverage the collapsible menu to shorten the Breadcrumb trail.
  • Only truncate the root page if absolutely necessary.
  • The current page is always visible and should never collapse into the overflow Menu.

When to Use

  • Use Breadcrumbs when users must navigate through a complex site or product.
  • Use Breadcrumbs to track hierarchical navigation.

When to Use Something Else

  • Use other components for primary navigation. Breadcrumbs are used to supplement a global or primary navigation.
  • Consider removing Breadcrumbs altogether if you have a flat hierarchy that is only 1 or 2 levels deep.

Examples

Basic Example

Breadcrumbs includes a container Breadcrumbs component and the following subcomponents which can be composed in a variety of ways: Breadcrumbs.List, Breadcrumbs.Item, Breadcrumbs.CurrentItem and Breadcrumbs.Link.

Accessibility is built into Breadcrumbs in a way that allows you to create an inclusive experience with little additional configuration. As seen in the example below, you don't need to pass any accessibility attributes, because they are baked into the component. You only need to add aria-label attribute to a nav component through a aria-label prop of Breadcrumbs.

Note that all links require an href to be properly identified.

Overflow Breadcrumbs

Breadcrumbs is a responsive component based on the width of its container. If the rendered links exceed the width of the Breadcrumbs.List, an overflow menu will be rendered. This only works against the dynamic API where you give the BreadcrumbsModel an array of items to be rendered. The dynamic API handles the React key for you based on the item's identifier. The dynamic API requires either an id on each item object or a getId function that returns an identifier based on the item. The example below uses an id property on each item.


Change Breadcrumb container size

The dynamic API takes in any object, but since nothing is known about your object, a render prop is necessary to instruct a list how it should render.

Right-to-Left (RTL)

Breadcrumbs has bidirectional support out of the box. That means outside of setting the content direction in your application's Canvas theme, you don't need to do anything else to make it work. All you need to supply is the translated text for items and ARIA labels.

Component API

Usage

Breadcrumbs is a container component that is responsible for creating a BreadcrumbsModel and sharing it with its subcomponents using React context. It also renders nav element, and aria-label attribute must be provided for this element.

<Breadcrumbs items={[]} aria-label="Breadcrumbs">
{/* Child components */}
</Breadcrumbs>

Alternatively, you may pass in a model using the hoisted model pattern.

const model = useBreadcrumbsModel({
items: [],
});
<Breadcrumbs model={model} aria-label="Breadcrumbs">
{/* Child components */}
</Breadcrumbs>;

Props

Note that if you pass in a model configured with useBreadcrumbsModel, configuration props passed to Breadcrumbs will be ignored. aria-label attribute must be provided for nav element.

All undeclared props go to underlying nav component.

NameTypeDefaultDescription
aria-label*stringThe accessibility label for the nav element. It's required to be provided by a11y guidance.
children*ReactNodeThe contents of the Breadcrumbs. Can be `Breadcrumbs` children or any valid elements.
idstring | undefineduseUniqueId()Optional id for the whole `Breadcrumbs` group. If not provided, a unique id will be created.
orientationOrientation | undefined'horizontal'The default Breadcrumbs component only handles rendering of the link group in a horizontal orientation, but the subcomponents could be replaced to handle vertical orientations.
menuConfigPartial<{ mode: "multiple" | "single"; returnFocusRef: RefObject<any> | undefined; initialFocusRef: RefObject<any> | undefined; id: string; initialVisibility: Visibility; ... 12 more ...; items: any[]; }> | undefined
initialHiddenIdsstring[] | undefined
containerWidthnumber | undefined
shouldCalculateOverflowboolean | undefinedtrueDetermines if overflow should actually occur. For example, touch devices are better at side-scrolling than mouse devices. In these cases, it makes sense to disable overflowing.
initialSelectedIdsSelectedIds | undefined
initialUnselectedIdsstring[] | undefined
selectionSelectionManager | undefined
initialCursorIdstring | undefined
columnCountnumber | undefined
navigationNavigationManager | undefined
getId((item: any) => string) | undefined
getTextValue((item: any) => string) | undefined
nonInteractiveIdsstring[] | undefined
defaultItemHeightnumber | undefined
shouldVirtualizeboolean | undefined
itemsany[] | undefined
refReact.Ref<any>Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If `as` is set to an element, it will be that element. If `as` is a component, the reference will be to that component (or element if the component uses `React.forwardRef`).
model{ state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; } | undefinedOptional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.
elemPropsHook(<TProps>(model: { state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | un...Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.
as"symbol" | "object" | "small" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | ... 156 more ... | React.ComponentType<any>Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using `React.forwardRef` and spread extra props to a root element.

Usage

Breadcrumbs.List is a Flex component rendered as a <ul> element. It is a container for Breadcrumbs.Item subcomponents. It also renders overflow button if overflowButton prop has been passed;

// without overflow
<Breadcrumbs.List>{/* Breadcrumbs.Items */}</Breadcrumbs.List>
// with overflow
<Breadcrumbs.List overflowButton={<Breadcrumbs.OverflowButton aria-label="More links" />}>
{/* Breadcrumbs.Items */}
</Breadcrumbs.List>

Props

Breadcrumbs.List accepts a overflowButton prop allowing to pass specific overflow button. Breadcrumbs.List with overflow behavior should contain overflowButton component with aria-label to render overflow button.

All undocumented props are spread to the underlying Flex component.

NameTypeDefaultDescription
overflowButtonReactNode
children*ReactNode | ((item: any, index: number) => ReactNode)If items are passed to a `BreadcrumbsModel`, the child of `Breadcrumbs.List` should be a render prop. The List will determine how and when the item will be rendered. @example <Breadcrumbs.List> {(item) => <Breadcrumbs.Item key={item.id} name={item.name}>{item.text}</Breadcrumbs.Item>} </Breadcrumbs.List>
refReact.Ref<any>Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If `as` is set to an element, it will be that element. If `as` is a component, the reference will be to that component (or element if the component uses `React.forwardRef`).
model{ state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; } | undefinedOptional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.
elemPropsHook(<TProps>(model: { state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | un...Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.
as"symbol" | "object" | "small" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | ... 156 more ... | React.ComponentType<any>Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using `React.forwardRef` and spread extra props to a root element.

Usage

Breadcrumbs.Item is a Flex component rendered as an <li> element. It is a container for the Breadcrumbs.Link subcomponent which provides correct overflow behavior across all items.

<Breadcrumbs.Item data-id="first">First Tab</Breadcrumbs.Item>

Props

Undocumented props are spread to the underlying Flex component.

Usage

Breadcrumbs.Link is a styled <a> element that also renders a tooltip if the text is truncated. The built-in truncation and tooltip functionality provides an easy-to-use, accessible feature for managing the length of link text. The maxWidth is set to 350px by default and can be adjusted as needed. Note that tooltips will only render when text is truncated. The example below uses a maxWidth of 150px.

Small Plates & Appetizers
Handling Redirects

Breadcrumbs.Link defaults to redirecting with an href, which means the page will hard-redirect when the link is clicked. However, if you're in a single-page application (SPA) environment, you might want to use the internal SPA router instead. You can override that behavior with a custom onClick handler that blocks the default behavior of the event and passes along the link path to your SPA router. Most of our consumers use react-router-dom for managing SPA routing, so below is an example of how to do this in V5 and V6 of react-router-dom.

// React Router DOM V5 API
import {useHistory} from 'react-router-dom';
import {Breadcrumbs} from '@workday/canvas-kit-react/breadcrumbs';
...
const history = useHistory();
const handleClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, link?: string) => {
event.preventDefault();
// if no link is provided, default to the current path
history.push(link || window.location.pathname);
}
return (
<Breadcrumbs.Link href="/account" onClick={handleClick}>
Account
</Breadcrumbs.Link>
);
// React Router DOM V6 API
import {useNavigate} from 'react-router-dom';
import {Breadcrumbs} from '@workday/canvas-kit-react/breadcrumbs';
...
const navigate = useNavigate();
const handleClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, link?: string) => {
event.preventDefault();
// if no link is provided, default to the current path
navigate(link || window.location.pathname);
}
return (
<Breadcrumbs.Link href="/account" onClick={handleClick}>
Account
</Breadcrumbs.Link>
);

Props

This component also supports all native <a> element props.

NameTypeDefaultDescription
href*stringThe href url of the anchor tag
maxWidthnumber | undefined350pxThe max-width of the link text
tooltipProps{} | OverflowTooltipProps | undefined
refReact.Ref<any>Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If `as` is set to an element, it will be that element. If `as` is a component, the reference will be to that component (or element if the component uses `React.forwardRef`).
as"symbol" | "object" | "small" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | ... 156 more ... | React.ComponentType<any>Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using `React.forwardRef` and spread extra props to a root element.

Usage

Breadcrumbs.CurrentItem is a styled <li> element that also renders a tooltip if the text is truncated. The built-in truncation and tooltip functionality provides an easy-to-use, accessible feature for managing the length of the text. The maxWidth is set to 350px by default and can be adjusted as needed. Normally, this is a non-focusable element; when truncated, however, it sets the tabIndex to 0 to enable the tooltip to appear on keyboard focus. Note that tooltips will only render when text is truncated. The example below uses a maxWidth of 100px.

Props

This component also supports all native <li> element props.

NameTypeDefaultDescription
tooltipPropsOverflowTooltipProps | undefined
typeLevel"body.small" | "body.large" | "body.medium" | "title.small" | "title.large" | "title.medium" | "heading.small" | "heading.large" | "heading.medium" | "subtext.small" | "subtext.large" | "subtext.medium" | undefinedType token as string with level and size separated by dot. These values map to our [Canvas type levels](https://canvas.workday.com/tokens/type#type-styles). @example ```tsx <Text typeLevel="body.small">Small body text</Text> ```
variantkeyof CanvasTypeVariants | undefinedType variant token names: `error`, `hint` or `inverse`. @example ```tsx <Text variant="error" typeLevel="subtext.large">Error text</Text> ```
refReact.Ref<any>Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If `as` is set to an element, it will be that element. If `as` is a component, the reference will be to that component (or element if the component uses `React.forwardRef`).
model{ state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; } | undefinedOptional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.
elemPropsHook(<TProps>(model: { state: { hiddenIds: string[]; nonInteractiveIds: string[]; orientation: Orientation; itemWidthCache: Record<string, number>; containerWidth: number; overflowTargetWidth: number; ... 10 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | un...Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.
as"symbol" | "object" | "small" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | ... 156 more ... | React.ComponentType<any>Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using `React.forwardRef` and spread extra props to a root element.

The Breadcrumbs.Menu uses the Menu component under the hood. Please view our Menu docs for more in-depth component information.

Model

If Breadcrumbs was stripped of all its markup, attributes, and styling, what would remain is the model. The model is an object composed of two parts: state which describes the current snapshot in time of the component and events which describes events that can be sent to the model.

By default, Breadcrumbs will create a model and share it internally with its subcomponents using React context. Alternatively, if you need direct access to the model's state and events outside of the Breadcrumbs component, you may configure your own model with useBreadcrumbsModel and pass it to Breadcrumbs via a pattern called hoisting the model.

const model = useBreadcrumbsModel({
items: [],
});
<Breadcrumbs model={model}>{/* Child components */}</Breadcrumbs>;

Config

useBreadcrumbsModel accepts a configuration object with the following properties and returns a BreadcrumbsModel with state and events properties.

NameTypeDefaultDescription
idstring | undefineduseUniqueId()Optional id for the whole `Breadcrumbs` group. If not provided, a unique id will be created.
orientationOrientation | undefined'horizontal'The default Breadcrumbs component only handles rendering of the link group in a horizontal orientation, but the subcomponents could be replaced to handle vertical orientations.
menuConfigPartial<{ mode: "multiple" | "single"; returnFocusRef: RefObject<any> | undefined; initialFocusRef: RefObject<any> | undefined; id: string; initialVisibility: Visibility; ... 12 more ...; items: any[]; }> | undefined
initialHiddenIdsstring[] | undefined
containerWidthnumber | undefined
shouldCalculateOverflowboolean | undefined
initialSelectedIdsSelectedIds | undefined
initialUnselectedIdsstring[] | undefined
selectionSelectionManager | undefined
initialCursorIdstring | undefined
columnCountnumber | undefined
navigationNavigationManager | undefined
getId((item: any) => string) | undefined
getTextValue((item: any) => string) | undefined
nonInteractiveIdsstring[] | undefined
defaultItemHeightnumber | undefined
shouldVirtualizeboolean | undefined
itemsany[] | undefined

State

The BreadcrumbsModel state is an object with the following properties.

NameTypeDefaultDescription
hiddenIds*string[]
nonInteractiveIds*string[]
orientation*Orientation
itemWidthCache*Record<string, number>
containerWidth*number
overflowTargetWidth*number
selectedIds*SelectedIds
unselectedIds*string[]
cursorId*string
columnCount*number
UNSTABLE_virtual*{ virtualItems: VirtualItem[]; totalSize: number; scrollToOffset: (index: number, options?: ScrollToOffsetOptions | undefined) => void; scrollToIndex: (index: number, options?: ScrollToIndexOptions | undefined) => void; measure: () => void; }
UNSTABLE_defaultItemHeight*number
containerRef*RefObject<HTMLDivElement>
id*string
indexRef*MutableRefObject<number>
isVirtualized*boolean
items*Item<any>[]

Events

The BreadcrumbsModel events is an object with the following properties.

NameTypeDefaultDescription
select*(data: { id: string; }) => void
setContainerWidth*(data: { width?: number | undefined; }) => void
setOverflowTargetWidth*(data: { width: number; }) => void
addItemWidth*(data: { id: string; width: number; }) => void
removeItemWidth*(data: { id: string; }) => void
addHiddenKey*(data: { id: string; }) => void
removeHiddenKey*(data: { id: string; }) => void
selectAll*() => void
unselectAll*() => void
registerItem*(data: { item: any; textValue: string; }) => void
goTo*(data: { id: string; }) => void
goToNext*() => void
goToPrevious*() => void
goToPreviousRow*() => void
goToNextRow*() => void
goToFirst*() => void
goToLast*() => void
goToFirstOfRow*() => void
goToLastOfRow*() => void
goToNextPage*() => void
goToPreviousPage*() => void
unregisterItem*(data: { id: string; }) => void
updateItemHeight*(data: { value: number; }) => void

Specifications

GivenWhenThen
the Basic example is rendered
    • it should not have any axe errors
    the Basic example is rendered
      • it should have an element with a role of "navigation"
      the Basic example is rendered
        • it should have an element with a label of "Breadcrumbs"
        the Basic example is rendered
          • it should have a role of "list" on the <ul> element
          the Basic example is rendered
            • it should have list item elements inside the "list"
            the Basic example is rendered
              • it should have "data-id" for list items
              the Basic example is rendered
              • a breadcrumb link is focused
              • it should show tooltips for truncated link items
              the Basic example is rendered
              • a breadcrumb link is focused
              • it should not show tooltips for not truncated link items
              the Basic example is rendered
              • a breadcrumb link is focused
              • AND THEN the tab key is pressed
              • it should move focus to the next link
              the Basic example is rendered
              • the last breadcrumb (current item) is focused
              • it should show a tooltip for the truncated text
              the Overflow Breadcrumbs example is rendered
                • it should not have any axe errors
                the Overflow Breadcrumbs example is rendered
                  • it should have aria-expanded set to "false" on the dropdown button
                  the Overflow Breadcrumbs example is rendered
                    • it should have aria-haspopup set to "true" on the dropdown button
                    the Overflow Breadcrumbs example is rendered
                      • it should have aria-controls set to "menu" on the dropdown button
                      the Overflow Breadcrumbs example is rendered
                      • the dropdown button is clicked
                      • it should toggle the button's aria-expanded attribute to true
                      the Overflow Breadcrumbs menu is rendered
                        • it should not have any axe errors
                        the Overflow Breadcrumbs menu is rendered
                          • it should have role set to "menu" on the dropdown menu
                          the Overflow Breadcrumbs menu is rendered
                            • it should have role set to "menuitem" for dropdown item link
                            the Overflow Breadcrumbs menu is rendered
                            • the dropdown menu is toggled with a keypress
                            • it should set focus to the first menu item
                            the Overflow Breadcrumbs menu is rendered
                            • the first menu item is focused
                            • it should toggle focus to the second menu item on down keypress
                            the Overflow Breadcrumbs menu is rendered
                            • the last menu item is focused
                            • it should roll the focus back to the first menu item on down keypress
                            the Overflow Breadcrumbs menu is rendered
                            • the down arrow key is pressed on the dropdown menu
                            • it should toggle focus to the next menu item on down keypress
                            the Overflow Breadcrumbs menu is rendered
                            • the up arrow key is pressed on the dropdown menu
                            • it should toggle focus to the previous list item
                            the Overflow Breadcrumbs menu is rendered
                            • the up arrow key is pressed on the dropdown menu
                            • it should return focus from the first menu item to the last
                            the Overflow Breadcrumbs menu is rendered
                            • the escape key is pressed on the dropdown menu
                            • it should return focus to the dropdown menu button
                            Source: Breadcrumbs.spec.ts

                            Accessibility Guidelines

                            • Breadcrumbs are navigational so the component should be encapsulated within a <nav> region.
                            • The <nav> region must have a uniquely descriptive accessible name for screen reader users to be able to distinguish Breadcrumbs among other <nav> regions on the page. (e.g. aria-label=”breadcrumb”)
                            • Breadcrumb links must be semantic <a> tags, with valid href attributes to ensure keyboard and screen reader accessibility.
                            • Constructing the list of links inside of a semantic unordered list markup with parent <ul> and child <li> tags will help provide further context to users about a given Breadcrumb’s position in a list, out of the total number of Breadcrumbs.
                            • All foreground text must meet a contrast ratio of 4.5:1 in relation to its background color.
                            • For accessibility guidelines related to the Breadcrumbs overflow menu, refer to our Menu component. For general accessibility considerations, refer to the Accessibility Guide.

                            Content Guidelines

                            Breadcrumb titles should inherit the same name as the page or product title the user has navigated to. When writing content for Breadcrumbs, refer to our Content Style Guide.

                            Can't Find What You Need?

                            Check out our FAQ section which may help you find the information you're looking for.

                            FAQ Section