Action Bar
Action Bars contain primary and secondary actions related to a page or task.
Component Type
Button
Platform
Web
Component
Sana Canvas
Delivery Channels
Web, Web Mobile
Version
16.1.7Experience Surfaces
Page Body Inline
Anatomy

- Primary Button: A button that is discoverable and used as the most important action to take on a page.
- Secondary Button: A button or set of buttons that is less important than the Primary Button.
- Overflow Menu: An Icon-Only Secondary Button Variant with an Ellipsis Icon used for responsive screens or small page width to show more actions.
- Container Bar: The Container Bar is used to house action buttons and is anchored at the bottom of the screen.
Usage Guidance
- Primary Buttons should only be used once per screen. If there are other buttons on screen, use the Secondary or Tertiary Buttons. However, Tertiary Buttons should not be on the Action Bar unless it’s in the Overflow Menu.
- Action Bars are placed at the bottom of the screen, and will stick as the user scrolls.
- Although actions may change, the placement of the Action Bar should persist until the task is successfully submitted.
- Action Bars can contain up to 3 actions and an Overflow Menu when appropriate.
- If there are more than 3 actions, hide the 4th and other remaining actions in an Overflow Menu that is launched by clicking the Icon Only Secondary Button Variant.
- There should be between 1-7 items to choose from in an Overflow Menu.
- Buttons placed in Action Bars should be grouped logically, either by usage or importance.
When to Use
- Use Action Bars for tasks that require navigating between pages, saving progress, submitting a task, or cancelling a task.
When to Use Something Else
- Consider taking a Button outside of the Action Bar if the action is not related to the progress or status of a task.
- Consider using a Text Button instead of an Action Bar if an action is less popular or less important.
Examples
Basic Example
ActionBar includes a container ActionBar component and the following subcomponent:
ActionBar.List which should contains ActionBar.Item.
In a basic example of an ActionBar there are two buttons. The primary action button should be used
only once and left aligned if content is left to right, followed by secondary buttons. Tertiary
buttons should not be used in the Action Bar.
import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
export default () => {
return (
<ActionBar>
<ActionBar.List position="relative" as="section" aria-label="Action Bar">
<ActionBar.Item as={PrimaryButton} onClick={() => console.log('first action')}>
First Action
</ActionBar.Item>
<ActionBar.Item>Second Action</ActionBar.Item>
</ActionBar.List>
</ActionBar>
);
};
Icons Example
ActionBar.Item renders a SecondaryButton as default, so it’s possible to use other Button props
with ActionBar.Item such as icon or size.
import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {alarmClockIcon, notificationsIcon} from '@workday/canvas-system-icons-web';
export default () => {
return (
<ActionBar>
<ActionBar.List position="relative" as="section" aria-label="Action Bar">
<ActionBar.Item as={PrimaryButton} icon={notificationsIcon}>
First Action
</ActionBar.Item>
<ActionBar.Item icon={alarmClockIcon}>Second Action</ActionBar.Item>
</ActionBar.List>
</ActionBar>
);
};
Delete Action Example
ActionBar.Item is a SecondaryButton by default but it’s posible to change it to another element,
such as DeleteButton, by using as prop.
import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import {DeleteButton} from '@workday/canvas-kit-react/button';
export default () => {
return (
<ActionBar>
<ActionBar.List position="relative" as="section" aria-label="Action Bar">
<ActionBar.Item as={DeleteButton}>Delete Action</ActionBar.Item>
<ActionBar.Item>Second Action</ActionBar.Item>
</ActionBar.List>
</ActionBar>
);
};
Overflow Example
ActionBar container can contain up to 3 actions and an Overflow Menu if there are more than 3
actions, the other remaining actions should be placed into an Overflow Menu that is launched by
clicking the Overflow Button.
Also, ActionBar is a responsive component based on the width of its container. If the rendered
actions exceed the width of the ActionBar.List, an overflow menu will be rendered. This only works
against the dynamic API where you give the ActionBarModel 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.
import React from 'react';
import {ActionBar, useActionBarModel} from '@workday/canvas-kit-react/action-bar';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {breakpoints} from '@workday/canvas-kit-react/common';
import {Box} from '@workday/canvas-kit-react/layout';
import {SegmentedControl} from '@workday/canvas-kit-react/segmented-control';
import {px2rem} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
type MyActionItem = {
id: string;
text: React.ReactNode;
};
export default () => {
const [items] = React.useState<MyActionItem[]>([
{id: 'first', text: 'First Action'},
{id: 'second', text: 'Second Action'},
{id: 'third', text: 'Third Action'},
{id: 'fourth', text: 'Fourth Action'},
{id: 'fifth', text: 'Fifth Action'},
]);
const model = useActionBarModel({items});
const [containerWidth, setContainerWidth] = React.useState<string | number>('100%');
return (
<div>
<Box cs={{maxWidth: containerWidth, marginBlockEnd: system.gap.xxl}}>
<ActionBar model={model}>
<ActionBar.List
position="relative"
as="section"
aria-label="Action Bar"
overflowButton={<ActionBar.OverflowButton aria-label="More actions" />}
>
{(item: MyActionItem, index) => (
<ActionBar.Item
as={index === 0 ? PrimaryButton : undefined}
onClick={() => console.log(item.id)}
>
{item.text}
</ActionBar.Item>
)}
</ActionBar.List>
<ActionBar.Menu.Popper>
<ActionBar.Menu.Card cs={{maxWidth: px2rem(300), maxHeight: px2rem(200)}}>
<ActionBar.Menu.List>
{(item: MyActionItem) => (
<ActionBar.Menu.Item onClick={() => console.log(item.id)}>
{item.text}
</ActionBar.Menu.Item>
)}
</ActionBar.Menu.List>
</ActionBar.Menu.Card>
</ActionBar.Menu.Popper>
</ActionBar>
</Box>
<footer>
<h4>Change Action Bar container size</h4>
<SegmentedControl onSelect={data => setContainerWidth(data.id)}>
<SegmentedControl.List role="group" aria-label="container width control">
<SegmentedControl.Item data-id="100%">100%</SegmentedControl.Item>
<SegmentedControl.Item data-id={`${breakpoints.m}px`}>Small</SegmentedControl.Item>
<SegmentedControl.Item data-id="420px">420px</SegmentedControl.Item>
<SegmentedControl.Item data-id={`${breakpoints.s}px`}>
Extra Small
</SegmentedControl.Item>
</SegmentedControl.List>
</SegmentedControl>
<br />
<p>Selected: {containerWidth}</p>
</footer>
</div>
);
};
The number of visible buttons can also be adjusted by using the model’s maximumVisible attribute.
You can change it from the default of 3 to any number greater than 1 and less than items.length.
import React from 'react';
import {ActionBar} from '@workday/canvas-kit-react/action-bar';
type MyActionItem = {
id: string;
text: React.ReactNode;
};
export default () => {
const [items] = React.useState<MyActionItem[]>([
{id: 'view', text: 'View'},
{id: 'edit', text: 'Edit'},
{id: 'delete', text: 'Delete'},
]);
return (
<ActionBar items={items} maximumVisible={2}>
<ActionBar.List
as="section"
aria-label="Custom button count overflow example"
position="relative"
overflowButton={<ActionBar.OverflowButton aria-label="More actions" />}
>
{(item: MyActionItem) => (
<ActionBar.Item onClick={() => console.log(item.id)}>{item.text}</ActionBar.Item>
)}
</ActionBar.List>
<ActionBar.Menu.Popper>
<ActionBar.Menu.Card>
<ActionBar.Menu.List>
{(item: MyActionItem) => (
<ActionBar.Menu.Item onClick={() => console.log(item.id)}>
{item.text}
</ActionBar.Menu.Item>
)}
</ActionBar.Menu.List>
</ActionBar.Menu.Card>
</ActionBar.Menu.Popper>
</ActionBar>
);
};
Accessibility
The primary accessibility goal is a clearly named group of page-level actions where every action is
a native, keyboard-operable button. Use Action Bar for the primary and secondary actions of a page
or task. For a single action, use a Button directly.
For a dense set of icon or dropdown controls that behaves as one tab stop, use
Toolbar . For
actions that open a task flow, compose Modal or
Dialog from an ActionBar.Item.
See the Menu Button pattern (APG) , the Button pattern (APG) , and the Canvas Kit Accessibility overview .
Minimum Accessible Structure
The following matches the Basic Example: an ActionBar.List rendered as a
labelled section, with a primary action first and secondary actions after it. ActionBar.List
and ActionBar.Item should always be inside ActionBar.
import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
<ActionBar>
<ActionBar.List as="section" aria-label="Page actions">
<ActionBar.Item as={PrimaryButton} onClick={() => console.log('first action')}>
First Action
</ActionBar.Item>
<ActionBar.Item>Second Action</ActionBar.Item>
</ActionBar.List>
</ActionBar>;Provide a translated, descriptive aria-label on ActionBar.List. Every
ActionBar.Item needs non-empty visible text, which becomes its accessible name.
Built-in Behaviors
Canvas Kit applies these automatically. Do not duplicate them in consuming code.
ARIA and DOM (applied by hooks/subcomponents):
ActionBar: Does not render an element. It creates the model and wraps its children inMenuso the overflow menu shares state.ActionBar.List: Renders adivby default. It has no role of its own—useas="section"witharia-labelto expose a landmark. It is positioned fixed to the bottom of the viewport unless you overrideposition.ActionBar.Item: Renders a native<button>throughSecondaryButton(or the component passed toas). It inherits the Button accessibility behavior, including visible label wiring and decorativeiconhandling.- Overflow: Items that do not fit, or that exceed
maximumVisible, receivearia-hidden,inert, anddisabled, so they are removed from the tab order and the accessibility tree and appear in the overflow menu instead. ActionBar.OverflowButton: Renders aSecondaryButtonwith the related-actions icon,aria-haspopup, andaria-expandedthrough theMenu.Target. It isaria-hiddenwithtabIndex={-1}while no items overflow, and gainstabIndex={0}once items overflow.ActionBar.Menu: Is the standard Menu.ActionBar.Menu.Listhasrole="menu"labelled by the overflow button, andActionBar.Menu.Itemhasrole="menuitem"with rovingtabIndex.
Focus (applied by the model):
- Opening the overflow menu moves focus to its first item.
- Selecting an item closes the menu.
- Closing the menu (Escape, outside click, or selection) returns focus to
ActionBar.OverflowButton.
Keyboard:
| Key | Behavior |
|---|---|
| Tab / Shift+Tab | Moves between each visible ActionBar.Item and the overflow button. Every visible item is its own tab stop; Action Bar does not use roving tabindex |
| Enter / Space | Activates the focused item, or opens the overflow menu |
| ArrowDown / ArrowUp | Opens the overflow menu from the overflow button |
| ArrowDown / ArrowUp inside menu | Moves between overflow menu items |
| Escape | Closes the overflow menu and returns focus to the overflow button |
| Tab inside menu | Closes the menu and moves focus to the next focusable element on the page |
Screen reader expectations (when built-in behaviors are used as intended):
- On entering the group, the landmark is announced with the
aria-label(for example, “Page actions, region”). - Each visible item is announced by its text and role (for example, “First Action, button”).
- The overflow button is announced with its
aria-labeland as a menu button with expanded or collapsed state (for example, “More actions, menu button, collapsed”). - Items moved into the overflow menu are no longer announced as buttons in the bar. They are announced as menu items when the menu is open.
Accessibility Requirements
Required in application code for an accessible Action Bar. Rows marked (conditional) apply only when the situation matches—otherwise omit.
If no design spec is provided: render ActionBar → ActionBar.List with as="section"
and a translated aria-label, one primary ActionBar.Item first, followed by secondary
ActionBar.Item components with visible text. Omit icon, disabled, the overflow API, custom
maximumVisible, and custom data-id unless the spec requires them.
| Requirement | How to satisfy |
|---|---|
| Group label | as="section" and a translated aria-label on ActionBar.List that is unique among landmarks on the page |
| Item accessible name | Non-empty visible text as the child of every ActionBar.Item |
| Composition order | ActionBar → ActionBar.List → ActionBar.Item; add ActionBar.Menu as a sibling of ActionBar.List for overflow |
| Primary action (conditional) | as={PrimaryButton} on only the first ActionBar.Item; secondary actions use the default; do not use TertiaryButton |
| Destructive action (conditional) | as={DeleteButton} only for destructive actions, per design |
| Decorative icon (conditional) | icon on ActionBar.Item with visible text—no extra ARIA on the icon |
| Overflow button name (conditional) | Translated aria-label on ActionBar.OverflowButton (required by its type), passed through overflowButton on ActionBar.List |
| Overflow menu (conditional) | Dynamic API: items on useActionBarModel, render props on both ActionBar.List and ActionBar.Menu.List, and ActionBar.Menu.Popper → Card → List → Item with the same item text |
| Menu item activation (conditional) | The same onClick handler on ActionBar.Item and its ActionBar.Menu.Item counterpart so an action behaves the same wherever it renders |
| Fixed placement (conditional) | ActionBar.List is position: fixed at the bottom of the viewport. Reserve space so page content and focused controls are not hidden behind it, or pass position="relative" when the bar sits in the page flow |
| Disabled action (conditional) | Native disabled on ActionBar.Item when the spec marks the action unavailable |
Summary for code generation:
- REQUIRED:
ActionBar.Listwithas="section"and a translatedaria-label; everyActionBar.Itemwith visible text; one primary action first - CONDITIONAL:
icon;DeleteButton;overflowButtonwith anaria-label; matchingActionBar.Menuitems and handlers;position="relative";disabled
Anti-Patterns
Do not generate code that does the following (see Accessibility Requirements above for what to supply instead):
- Omit
as="section"oraria-labelonActionBar.List, which leaves the group unidentifiable to screen reader users - Reuse the same
aria-labelforActionBar.Listand another landmark on the page - Use more than one
PrimaryButtonor anyTertiaryButtonin an Action Bar - Render
ActionBar.Itemwithout visible text or as a non-button element withonClick - Add
role="toolbar",role="group", roving tabindex, or arrow-key handlers toActionBar.List—each item must be a separate tab stop - Render
ActionBar.OverflowButtonwithoutaria-label - Set
aria-haspopup,aria-expanded, oraria-hiddenonActionBar.OverflowButtonorActionBar.Item—the model sets them - Hide overflowing items with CSS,
hidden, or conditional rendering—use the dynamic API andmaximumVisible - Use the overflow behavior with static children—it requires
itemson the model and render props - Provide an overflow menu whose items differ in text or behavior from the action bar items
- Move focus manually after the overflow menu closes—
Menureturns focus to the overflow button - Leave the fixed
ActionBar.Listcovering page content or focused controls
Component API
ActionBar
ActionBar is a container component that is responsible for creating an and sharing it with its subcomponents using React context. It does not represent a real element.
<ActionBar items={[]}>{Child components}</ActionBar>
Alternatively, you may pass in a model using the hoisted model pattern.
const model = useActionBarModel({
items: [],
});
<ActionBar model={model}>{Child components}</ActionBar>;
Props
Props extend from . If a model is passed, props from ActionBarModelConfig are ignored.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The contents of the ActionBar. Can be | |
model | | Optional 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 | ( | 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. |
ActionBar.List
ActionBar.List is a element. It is a container for
subcomponents. To render an overflow button for
ActionBar with overflow behavior overflowButton prop with overflow button component as a
value should be passed.
// without overflow
<ActionBar.List>{ActionBar.Items}</ActionBar.List>
// with overflow
<ActionBar.List overflowButton={<ActionBar.OverflowButton aria-label="More actions"/>}>
{ActionBar.Items}
</ActionBar.List>
Layout Component
ActionBar.List supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | (( | If items are passed to a | |
overflowButton | ReactNode |
| |
cs | | The | |
as | React.ElementType | 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 Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional 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 | ( | 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. |
useOverflowListMeasure
This elemProps hook measures a list and reports it to an OverflowListModel. This is used in
overflow detection.
(
model: ,
elemProps: {},
ref: React.Ref
) => {
ref: (instance: | null) => void;
}ActionBar.Item
ActionBar.Item is a button element, by default it's a SecondaryButton unless an as
prop is passed.
<ActionBar.Item as={PrimaryButton} onClick={() => console.log('first action')}>
First Action
</ActionBar.Item>
Props
Props extend from . Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The contents of the action item. This will be the accessible name of the action for screen readers. | |
data-id | string | The identifier of the action. This identifier will be used for correct overflow behavior. If this property is not provided, it will default to a string representation of the the zero-based index of the Item when it was initialized. | |
as | React.ElementType | 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 Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | |
ref | React.Ref<R = > | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional 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 | ( | 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. |
ActionBar.OverflowButton
Props
Props extend from button. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
aria-label | string | Defines a string value that labels the current element. | |
variant | 'inverse' | Variant has an option for | |
iconPosition | 'start' | 'end' | Button icon positions can either be | 'start' |
shouldMirrorIcon | boolean | If set to | false |
shouldMirrorIconInRTL | boolean | If set to | false |
size | | There are four button sizes: | |
colors | | Override default colors of a button. The default will depend on the button type | |
icon | | The icon of the Button.
Note: Not displayed at | |
shouldMirror | boolean | If set to | false |
shouldMirrorInRTL | boolean | If set to | false |
cs | | The | |
color | string | The color of the SystemIcon. This defines | |
children | ReactNode | ||
accent | string | The accent color of the SystemIcon. This overrides | |
background | string | The background color of the SystemIcon. | |
fillIcon | boolean | Whether the icon should received filled (colored background layer) or regular styles.
Corresponds to | |
grow | boolean | True if the component should grow to its container's width. False otherwise. | |
as | React.ElementType | 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 Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | button |
ref | React.Ref<R = button> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional 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 | ( | 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. |
useActionBarOverflowButton
(
(
model: ,
elemProps: {},
ref: React.Ref
) => {
aria-haspopup: true;
},
,
(
(model: ) => ,
)
)ActionBar.Menu
Basic type information:
Menu