Tabs

Allows the user to alternate between related views while remaining in the same context.

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

Anatomy

Image of a Card with annotation markers.

  1. Active Tab: The tab that is selected and currently displaying it's contents.
  2. Inactive Tab: All of the other unselected, available tabs.
  3. Active Chip: Highlights the active tab.
  4. Divider Line: Spans the width of the entire tabs container separating the tab set from its contents.

Usage Guidance

  • Tabs are used to help the user navigate through information while remaining in context of the page. This is the most important reason to use Tabs. Users should not navigate to a different page when interacting with Tabs.
  • Content that is grouped within a Tab should always be related so that the user knows what to expect when they navigate each Tab. Never force users to switch back and forth between Tabs to complete a task.
  • Tab labels should be concise, scannable, and descriptive of their contents. Avoid using multiple words for Tab labels. Never use icons. To reduce cognitive load and a cluttered UI, avoid using more than 6 Tabs.
  • Tabs should directly relate to the page section they’re within.
  • The Tab divider line should span the full width of its container and create a clear distinction between what’s under the Tab sections and the rest of the page.
  • Do not use Tabs as a primary form of navigation.
  • When there are too many tabs to display at once, use the overflow menu to indicate that more Tabs are available.
  • The recommended minimum width of a tab is 88px, standard padding to the left and right is 24px, and minimum padding is 16px.
  • You can place most components within Tabs, because they operate like mini-pages. For example, Grids, Field Sets, and Prompts can all be added within a tabbed page.
  • You can use fixed Tabs, especially when the contents of a tab is scrollable.

When To Use

  • When content can be grouped into logical sections in order to avoid overwhelming the user with a lot of information. Tabs should cater for distinct groups of information.
  • To alternate between two or more sections of organized content while keeping the user in-context of the greater UI.
  • Use Tabs to help section off and organize related content.
  • When you have an abundance of related content to house in a small container.

When To Use Something Else

  • Consider an alternative solution if the information within multiple Tabs needs to be viewed simultaneously. Tabs are not suitable for comparing information or data, as it forces the user to rely on short term memory when switching back and forth between Tabs.
  • Consider using a more prominent, alternative form of navigation when there is a need for more than 6 or 7 Tabs.
  • Avoid using Tabs within a card UI.
  • If the content on a page is cohesive and doesn’t take up too much space, Tabs are likely unnecessary.
  • When Tabs are already being used on the page.

Variations

TypePurpose
Default/StandardShould be used in most use cases for tabs.
Full-WidthExclusively used in smaller containers ~300-400px width (e.g. within side panels or responsive UI).
  • No margin between Tabs. Tab widths are evenly proportioned, defined by its container.
  • Active chip spans full-width of the active Tab.
  • 2-3 Tabs max for this variation.
  • Do not use on large desktop experiences. More suitable for container widths less than 400px.
Wrapped TabsEdge case for when there is a requirement to have lengthy or multiple words for a Tab label.
  • Max of two lines wrapped.
  • This variation increases the overall Tab set height.

States and Behavior

  • By default, Tabs should always contain one Tab with an active state.
  • Only one Tab can have an active state at a time.
  • The inactive state of a Tab can inherit a hover, focus, and selected state.
  • The active state of a Tab can only inherit a focus state.

Coming Soon with Tabs Phase 2

  • Overflow menu and responsive treatment.
  • Scrolling behavior if applicable.

Examples

Basic Example

Tabs includes a container Tabs component and the following subcomponents which can be composed in a variety of ways: Tabs.List, Tabs.Item and Tabs.Panel. It follows the W3 Tabs specification.

In this example, we set up a basic Tabs component with five tabs. This example uses a static API that does not support overflow.

Contents of First Tab
Contents of Second Tab
Contents of Third Tab
Contents of Fourth Tab
Contents of Fifth Tab

Overflow Tabs

Tabs is a responsive component based on the width of its container. If the rendered tabs exceed the width of the Tabs.List, an overflow menu will be rendered. This only works against the dynamic API where you give the TabsModel 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 below example uses an id property on each item.

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.

Contents of First Tab

Change tab container size

Hoisted Model

By default, Tabs will create and use its own model internally. Alternatively, you may configure your own model with useTabsModel and pass it to Tabs via the model prop. This pattern is referred to as hoisting the model and provides direct access to its state and events outside of the Tabs component.

In this example, we set up external observation of the model state and create an external button to trigger an event to change the active tab.

Named Tabs

Tabs.Item and Tabs.Panel both take an optional data-id attribute that is used for the onActivate callback. This example is identical to the Basic Example, but with tabs named using data-id for the Tabs.Item and Tabs.Panel subcomponents.

Right-to-Left (RTL)

Tabs supports right-to-left languages when specified in the CanvasProvider theme.

תוכן הראשון
תוכן השני
תוכן השלישי
תוכן הרביעי
תוכן החמישי

Disabled Tab

Set the disabled prop of a Tabs.Item to true to disable it.

Contents of First Tab
Contents of Disabled Tab
Contents of Third Tab

Tab Icons

Tabs can have icons. Use the Icon and Text subcomponents.

Contents of First Tab
Contents of Second Tab
Contents of Third Tab
Contents of Fourth Tab

Alternative Tab Stop

By default, tab panels are focusable for accessibility. If the contents of a tab panel have a focusable element, you may disable this default behavior by setting the tabIndex prop of Tabs.Panel to undefined. This example has a tab panel with a focusable button.


Contents of First Tab. The tab panel is no longer focusable, but the button is. It may be desirable to disable focus on the tab panel and allow focus to flow into the tab panel to the first focusable element.
Contents of Second Tab
Contents of Third Tab

Single Tab Panel

The compound component pattern allows for advanced composition. For example, Tabs can be composed to have only a single Tabs.Panel using attribute overrides and callbacks. More information about attributes and callbacks can be found in the prop tables below for each subcomponent.

In this example, we use a hoisted model and the activeTab property of the state to show content from the contents object.

Dynamic Tabs

The Tabs.Item component takes in an optional index property if you want to specify the position of a tab. If not defined, by default it will append tabs to the end. In this example, our tabs are stored as an array in the state, and we have a fixed tab at the end that can add new tabs to that array.

Contents of Tab 1

Component API

Tabs

Usage

Tabs is a container component that is responsible for creating a TabsModel and sharing it with its subcomponents using React context. It does not represent a real element.

<Tabs onSelect={data => console.log('Activated tab', data.id)}>{/* Child components */}</Tabs>

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

const model = useTabsModel({
onSelect(data) {
console.log('Activated Tab', data.id);
},
});
<Tabs model={model}>{/* Child components */}</Tabs>;

Props

Note that if you pass in a model configured with useTabsModel, configuration props passed to Tabs will be ignored.

NameTypeDefaultDescription
children*ReactNodeThe contents of the Tabs. Can be `Tabs` children or any valid elements.
idstring | undefineduseUniqueId()Optional id for the whole `Tabs` group. The `aria-controls` of the `Tab.Item` and `id` of the `Tab.Panel` will automatically derived from this id. If not provided, a unique id will be created.
initialTabstring | undefinedAn initially selected tab. This value must match the `name` of the `Tab.Item` component. If not provided, the first tab will be selected.
orientationOrientation | undefined'horizontal'The default Tabs sub-components only handle rendering of tabs in a horizontal orientation, but the sub-components 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
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
model{ state: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | undefinedOptional 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.

Tabs.List

Usage

Tabs.List is a <div role="tablist"> element. It is a container for Tabs.Item subcomponents.

<Tabs.List>{/* Tabs.Items */}</Tabs.List>

Props

Undocumented props are spread to the underlying <div> element.

NameTypeDefaultDescription
children*ReactNode | ((item: unknown) => ReactNode)If items are passed to a `TabsModel`, the child of `Tabs.List` should be a render prop. The List will determine how and when the item will be rendered. @example <Tabs.List> {(item) => <Tabs.Item>{item.text}</Tabs.Item>} </Tabs.List>
overflowButtonReactNode
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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | undefinedOptional 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.

Tabs.Item

Usage

Tabs.Item is a <button role="tab"> element. Each Tabs.Item is associated with a Tabs.Panel either by a data-id attribute or by the position in the list. If a data-id is provided, it must match the data-id passed to the corresponding Tabs.Panel component.

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

Props

Undocumented props are spread to the underlying button element.

NameTypeDefaultDescription
indexnumber | undefinedOptionally pass index to tab item. This should be done if `Tabs.Item` components were created via a `Array::map` function. This index will ensure keyboard navigation works even if items are inserted out of order.
children*ReactNodeThe contents of the tab item. This will be the accessible name of the tab for screen readers. Often, this is text. Icons are also supported. Using `Tabs.Icon` will render an icon that is not visible to screen readers and therefore the icon should not be necessary to understand the tab. In most circumstances, `aria-label` should not be used. ```tsx <Tabs.Item>First Tab</Tabs.Item> <Tabs.Item> <Tabs.Icon icon={canvasIcon} /> <Tabs.Text>Second Tab</Tabs.Text> </Tabs.Item> ```
data-idstring | undefinedThe identifier of the tab. This identifier will be used in change events and for `initialTab`. Must match the `data-id` of the associated tab panel. If this property is not provided, it will default to a string representation of the the zero-based index of the Tab when it was initialized.
idstring | undefinedOptional id. If not set, it will inherit the ID passed to the `Tabs` component and append the index at the end. Only set this for advanced cases.
aria-controlsstring | undefinedPart of the ARIA specification for tabs. This attributes links a `role=tab` to a `role=tabpanel`. This value must be the same as the associated `id` attribute of the tab panel. This is automatically set by the component and should only be used in advanced cases.
aria-selectedboolean | undefinedPart of the ARIA specification for tabs. Lets screen readers know which tab is active. This should either be `true` or `undefined` and never `false`. This is automatically set by the component and should only be used in advanced cases.
tabIndexnumber | undefinedPart of the ARIA specification for tabs. The currently active tab should not have a `tabIndex` set while all inactive tabs should have a `tabIndex={-1}`
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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | undefinedOptional 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.

Tabs.Panel

Usage

Tabs.Panel is a <div role="tabpanel"> element. It is focusable by default. Each Tabs.Panel is controlled by a Tabs.Item either by a data-id attribute or by the position in the list. If a data-id is provided, it must match the data-id passed to the corresponding Tabs.Item component.

<Tabs.Panel data-id="first">{/* Contents of the tab panel */}</Tabs.Panel>

Props

Undocumented props are spread to the underlying <div> element.

NameTypeDefaultDescription
children*ReactNodeThe contents of the TabPanel.
data-idstring | undefinedThe identifier of the tab. This identifier will be used in change events and for `initialTab`. Must match the `data-id` of the associated tab item. If this property is not provided, it will default to a string representation of the the zero-based index of the Tab when it was initialized.
tabIndexnumber | undefinedPart of the ARIA specification for tabs. By default, all `tabpanel` elements have a `tabIndex` of `0` which makes the whole content area receive focus. If you have a focusable item near the top of the tab panel content area, you may set `tabIndex` to `undefined` to prevent the tab panel element from receiving focus. Only do this is a child of the tab panel can receive focus.
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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 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: { getId: (item: any) => string; orientation: Orientation; panels: Item<any>[]; panelIndexRef: MutableRefObject<number>; hiddenIds: string[]; ... 14 more ...; items: Item<...>[]; }; ... 4 more ...; getId: (item: any) => string; }, elemProps: TProps) => any) | undefinedOptional 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.

Model

If Tabs 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, Tabs 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 Tabs component, you may configure your own model with useTabsModel and pass it to Tabs via a pattern called hoisting the model.

const model = useTabsModel({
onActivate({data}) {
console.log('Activated Tab', data);
},
});
<Tabs model={model}>{/* Child components */}</Tabs>;

Config

useTabsModel accepts a configuration object with the following properties and returns a TabsModel with state and events properties.

NameTypeDefaultDescription

State

The TabsModel state is an object with the following properties.

NameTypeDefaultDescription

Events

The TabsModel events is an object with the following properties.

NameTypeDefaultDescription

Specifications

GivenWhenThen
the Basic story is rendered
    • it should pass axe checks
    the Basic story is rendered
      • it should have an element with a role of "tablist"
      the Basic story is rendered
        • it should have elements with a role of "tab" inside the "tablist"
        the Basic story is rendered
          • it should have "aria-selected=true" for the first tab
          the Basic story is rendered
            • it should not have "aria-selected" for the second tab
            the Basic story is rendered
              • it should not have tabindex=-1 on the first tab
              the Basic story is rendered
                • it should have "tabindex=-1" on the second tab
                the Basic story is rendered
                  • it should have an id on the first tab
                  the Basic story is rendered
                    • it should label the tab panel "First Tab"
                    the Basic story is rendered
                      • it should have an "aria-controls" on the first tab
                      the Basic story is rendered
                        • it should have an "aria-controls" that matches the first tab panel
                        the Basic story is rendered
                          • it should have a default cursor for the (active) first tab
                          the Basic story is rendered
                            • it should have a pointer cursor for the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the tab key is pressed
                            • it should move focus to the tabpanel
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • it should have tabindex=-1 on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • it should not have tabindex=-1 on the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • it should focus on the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the space key is pressed
                            • it should not have "aria-selected" on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the space key is pressed
                            • it should have "aria-selected=true" on the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the enter key is pressed
                            • it should not have "aria-selected" on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the enter key is pressed
                            • it should have "aria-selected=true" on the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the tab key is pressed
                            • it should focus on the tab panel of the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the tab key is pressed
                            • AND THEN shift + tab keys are pressed
                            • it should not have tabindex=-1 on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the tab key is pressed
                            • AND THEN shift + tab keys are pressed
                            • it should set "tabindex=-1" on the second tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the right arrow key is pressed
                            • AND THEN the tab key is pressed
                            • AND THEN shift + tab keys are pressed
                            • it should focus on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the left arrow is pressed
                            • it should have tabindex=-1 on the first tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the left arrow is pressed
                            • it should not have tabindex=-1 on the last tab
                            the Basic story is rendered
                            • the first tab is active and focused
                            • AND THEN the left arrow is pressed
                            • it should focus on the last tab
                            the Basic story is rendered
                            • the fifth tab is clicked
                            • it should show the contents of the fifth tab
                            the Basic story is rendered
                            • the fifth tab is clicked
                            • AND THEN the right arrow key is pressed
                            • it should not have tabindex=-1 on the first tab
                            the Basic story is rendered
                            • the fifth tab is clicked
                            • AND THEN the right arrow key is pressed
                            • it should set "tabindex=-1" on the last tab
                            the Named Tabs story is rendered
                              • it should pass axe checks
                              the Named Tabs story is rendered
                                • it should have an element with a role of "tablist"
                                the Named Tabs story is rendered
                                  • it should have elements with a role of "tab" inside the "tablist"
                                  the Named Tabs story is rendered
                                    • it should have "aria-selected=true" for the first tab
                                    the Named Tabs story is rendered
                                      • it should not have "aria-selected" for the second tab
                                      the Named Tabs story is rendered
                                        • it should not have tabindex=-1 on the first tab
                                        the Named Tabs story is rendered
                                          • it should have "tabindex=-1" on the second tab
                                          the Named Tabs story is rendered
                                            • it should have an id on the first tab
                                            the Named Tabs story is rendered
                                              • it should label the tab panel "First Tab"
                                              the Named Tabs story is rendered
                                                • it should have an "aria-controls" on the first tab
                                                the Named Tabs story is rendered
                                                  • it should have an "aria-controls" that matches the first tab panel
                                                  the Named Tabs story is rendered
                                                    • it should have a default cursor for the (active) first tab
                                                    the Named Tabs story is rendered
                                                      • it should have a pointer cursor for the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the tab key is pressed
                                                      • it should move focus to the tabpanel
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • it should have tabindex=-1 on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • it should not have tabindex=-1 on the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • it should focus on the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the space key is pressed
                                                      • it should not have "aria-selected" on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the space key is pressed
                                                      • it should have "aria-selected=true" on the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the enter key is pressed
                                                      • it should not have "aria-selected" on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the enter key is pressed
                                                      • it should have "aria-selected=true" on the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the tab key is pressed
                                                      • it should focus on the tab panel of the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the tab key is pressed
                                                      • AND THEN shift + tab keys are pressed
                                                      • it should not have tabindex=-1 on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the tab key is pressed
                                                      • AND THEN shift + tab keys are pressed
                                                      • it should set "tabindex=-1" on the second tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the tab key is pressed
                                                      • AND THEN shift + tab keys are pressed
                                                      • it should focus on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow is pressed
                                                      • it should have tabindex=-1 on the first tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow is pressed
                                                      • it should not have tabindex=-1 on the last tab
                                                      the Named Tabs story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow is pressed
                                                      • it should focus on the last tab
                                                      the Named Tabs story is rendered
                                                      • the fifth tab is clicked
                                                      • it should show the contents of the fifth tab
                                                      the Named Tabs story is rendered
                                                      • the fifth tab is clicked
                                                      • AND THEN the right arrow key is pressed
                                                      • it should not have tabindex=-1 on the first tab
                                                      the Named Tabs story is rendered
                                                      • the fifth tab is clicked
                                                      • AND THEN the right arrow key is pressed
                                                      • it should set "tabindex=-1" on the last tab
                                                      the DisabledTab story is rendered
                                                      • the Disabled Tab is clicked
                                                      • it should not set "[aria-selected=true]" on the Disabled Tab
                                                      the DisabledTab story is rendered
                                                      • the Disabled Tab is clicked
                                                      • it should leave the first tab selected
                                                      the DisabledTab story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • it should focus on the Disabled Tab
                                                      the DisabledTab story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the enter key is pressed
                                                      • it should not set "[aria-selected=true]" on the Disabled Tab
                                                      the DisabledTab story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow key is pressed
                                                      • AND THEN the enter key is pressed
                                                      • it should leave the first tab selected
                                                      the DynamicTabs story is rendered
                                                      • "Add Tab" is clicked
                                                      • it should focus on "Add Tab"
                                                      the DynamicTabs story is rendered
                                                      • "Add Tab" is clicked
                                                      • AND THEN the left arrow key is pressed
                                                      • it should focus on Tab 4
                                                      the DynamicTabs story is rendered
                                                      • "Tab 1" is activated
                                                      • AND THEN the Delete key is pressed
                                                      • it should have "aria-selected=true" for "Tab 2"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 1" is activated
                                                      • AND THEN the Delete key is pressed
                                                      • it should show "Tab 2" contents
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the Delete key is pressed
                                                      • it should remove "Tab 2"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the Delete key is pressed
                                                      • it should move focus to "Tab 3"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the Delete key is pressed
                                                      • it should have "aria-selected=true" for "Tab 3"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the Delete key is pressed
                                                      • it should show "Tab 3" contents
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the Delete key is pressed
                                                      • AND THEN the Delete key is pressed again
                                                      • it should move focus to "Add Tab"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed twice
                                                      • AND THEN the Delete key is pressed
                                                      • it should remove "Tab 1"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed twice
                                                      • AND THEN the Delete key is pressed
                                                      • it should move focus to "Tab 2"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed twice
                                                      • AND THEN the Delete key is pressed
                                                      • it should have "aria-selected=true" for "Tab 3"
                                                      the DynamicTabs story is rendered
                                                      • "Tab 3" is activated
                                                      • AND THEN the left arrow key is pressed twice
                                                      • AND THEN the Delete key is pressed
                                                      • it should show "Tab 3" contents
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the tab key is pressed
                                                      • it should move focus to the tabpanel
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow key is pressed
                                                      • it should have tabindex=-1 on the first tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow key is pressed
                                                      • it should not have tabindex=-1 on the second tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow key is pressed
                                                      • it should focus on the second tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the space key is pressed
                                                      • it should not have "aria-selected" on the first tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the left arrow key is pressed
                                                      • AND THEN the space key is pressed
                                                      • it should have "aria-selected=true" on the second tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow is pressed
                                                      • it should have tabindex=-1 on the first tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow is pressed
                                                      • it should not have tabindex=-1 on the last tab
                                                      the LeftToRight story is rendered
                                                      • the first tab is active and focused
                                                      • AND THEN the right arrow is pressed
                                                      • it should focus on the last tab
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • it should pass axe checks
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • it should not show the "More" button
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN the "First Tab" is focused
                                                      • AND THEN the Tab key is pressed
                                                      • it should focus on the tab panel
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • it should pass axe checks
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • it should show the "More" button
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • AND THEN the "First Tab" is focused
                                                      • AND THEN the Tab key is pressed
                                                      • it should focus on the "More" button
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • AND THEN the "More" button is clicked
                                                      • it should show the Tab overflow menu
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • AND THEN the "More" button is clicked
                                                      • AND THEN the "Sixth Tab" is clicked
                                                      • it should select the Sixth Tab
                                                      Could not find a "given". Check the spec file.
                                                      • [Components/Containers/Tabs/React, OverflowTabs] story is rendered
                                                      • AND THEN tab list container is only 500px wide
                                                      • AND THEN the "More" button is clicked
                                                      • AND THEN the "Sixth Tab" is clicked
                                                      • it should move focus back to the "More" button
                                                      Source: Tabs.spec.ts

                                                      Accessibility Guidelines

                                                      Keyboard Navigation

                                                      • Single keyboard tab stop for the Tab List
                                                      • Left / Right Arrow keys navigate among page tabs
                                                      • Enter and Space activate the focused page tab
                                                      • Home and End keys navigate to first and last page tab respectively
                                                      • Each tab is associated with a tab panel via aria-controls
                                                      • Each tab panel must be focusable or have an element inside the panel that is focusable
                                                      • The tab panel is the next tab stop after the tab list
                                                      • If the tab list has a visible label, then it must have an aria-labelledby attribute referencing the ID of the label. Otherwise, it must have an aria-label attribute

                                                      Screen Reader Listening Experience

                                                      • Announce the Tab list’s associated visible label
                                                      • Announce the focused tab name, role “tab”, and index X of total Y page tabs in the list
                                                      • Announce which one of the page tabs has been selected

                                                      Content Guidelines

                                                      • When writing tab labels, be concise and avoid using multiple words when possible. Labels should clearly describe the contents of the tab to the user.
                                                      • The page or page section title (if applicable) should make clear sense when placed after the tab name. Try to imagine the page title is a noun after the tab label. For example: If the page is titled “Fruit”, and the tabs are labeled “ripe” and “rotten”. You could read it in your head as “ripe fruit” or “rotten fruit”.
                                                      • Refer to the UI Text > Tabs section of the Content Style Guide when writing tab labels.

                                                      Can't Find What You Need?

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

                                                      FAQ Section