Action Bar

Action Bars contain primary and secondary actions related to a page or task.

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

Anatomy

Image of a Action Bar with one primary button, two secondary buttons and an Icon Button.

  1. Primary Button: A button that is discoverable and used as the most important action to take on a page.
  2. Secondary Button: A button or set of buttons that is less important than the Primary Button.
  3. Overflow Menu: An Icon-Only Secondary Button Variant with an Ellipsis Icon used for responsive screens or small page width to show more actions.
  4. 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.

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.

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.

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.


Change action bar container size

Component API

ActionBar

Usage

ActionBar is a container component that is responsible for creating a ActionBarModel 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

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

NameTypeDefaultDescription
children*ReactNodeThe contents of the ActionBar. Can be `ActionBar` children or any valid elements.
idstring | undefineduseUniqueId()Optional id for the whole `ActionBar` group. If not provided, a unique id will be created.
orientationOrientation | undefined'horizontal'The default ActionBar sub-components only handle rendering of button group 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
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
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.

ActionBar.List

Usage

ActionBar.List is a HStack element. It is a container for ActionBar.Item subcomponents. To render an overflow button for ActionBar with overflow behavior overflowButton prop with overflow button component as a value shold 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>

Props

Undocumented props are spread to the underlying HStack element.

NameTypeDefaultDescription
children*ReactNode | ((item: any, index: number) => ReactNode)If items are passed to a `ActionBarModel`, the child of `ActionBar.List` should be a render prop. The List will determine how and when the item will be rendered. @example <ActionBar.List> {(item) => <ActionBar.Item key={item.id} name={item.name}>{item.text}</ActionBar.Item>} </ActionBar.List>
overflowButtonReactNode`ActionBar.List` will render overflow button component if it's passed in `overflowButton`. @example <ActionBar.List overflowButton={<ActionBar.OverflowButton aria-label="More actions" />}> {(item) => <ActionBar.Item>{item.text}</ActionBar.Item>} </ActionBar.List>
flexDirection"row" | "row-reverse" | undefined"row"sets the direction for the stack
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.

ActionBar.Item

Usage

ActionBar.Item is a button element, by default it's a SecondaryButton unless an as prop passed.

<ActionBar.Item as={PrimaryButton} onClick={() => console.log('first action')}>
First Action
</ActionBar.Item>

Props

Undocumented props are spread to the underlying SecondaryButton component.

NameTypeDefaultDescription
children*ReactNodeThe contents of the action item. This will be the accessible name of the action for screen readers. ```tsx <ActionBar.Item>First Action</ActionBar.Item> ```
data-idstring | undefinedThe 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.
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.

Model

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

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

Config

useActionBarModel accepts a configuration object with the following properties and returns a ActionBarModel with state and events properties.

Accessibility Guidelines

  • The Button text and background color must meet the minimum contrast requirement.
  • If an Icon Only Secondary Button Variant is used within an Action Bar, an accessible label must be provided to indicate the purpose of the control. Avoid using the words "image" or "icon" in the description label.

Content Guidelines

Can't Find What You Need?

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

FAQ Section