useToolbar

Handles interactions for toolbar elements, such as keyboard navigation between elements.

installyarn add react-aria
version3.30.0
usageimport {useToolbar} from 'react-aria'

API#


useToolbar( (props: AriaToolbarProps, , ref: RefObject<HTMLDivElement> )): ToolbarAria

Features#


There is no native element to implement a toolbar in HTML without Javascript. useToolbar helps achieve accessible toolbar components that can be styled as needed.

  • Exposed to assistive technology as a toolbar or group element via ARIA
  • Support for keyboard navigation
  • Support for both horizontal and vertical orientations
  • Support for React Aria based children: button, togglebutton, menu, checkbox, and link
  • Automatic scrolling support during keyboard navigation

Anatomy#


ToolbarGroupCutCutCutCutCutPasteCopyButtonCutCutCutCutGroupSeparator

A toolbar consists of a wrapper element with role toolbar and groups of interactive children. useToolbar handles exposing this to assistive technology using ARIA, along with handling keyboard, mouse, and interactions to support navigation behavior.

useToolbar returns props that you should spread onto the appropriate element:

NameTypeDescription
toolbarPropsHTMLAttributes<HTMLElement>Props for the toolbar container.

If a toolbar does not have a visible label, an aria-label or aria-labelledby prop must be passed instead to identify the element to assistive technology.

Example#


Toolbar#

This uses the useToolbar hook, spread on a container to handle navigation of components inside it.

import {useToolbar} from 'react-aria';
import {useRef} from 'react';

// Reuse the Button from your component library. See below for details.
import {Button} from 'your-component-library';

function Toolbar(props) {
  let ref = useRef(null);
  // Get props for the toolbar element
  let { toolbarProps } = useToolbar(props, ref);

  return (
    <div {...toolbarProps} ref={ref}>
      {props.children}
    </div>
  );
}
import {useToolbar} from 'react-aria';
import {useRef} from 'react';

// Reuse the Button from your component library. See below for details.
import {Button} from 'your-component-library';

function Toolbar(props) {
  let ref = useRef(null);
  // Get props for the toolbar element
  let { toolbarProps } = useToolbar(props, ref);

  return (
    <div {...toolbarProps} ref={ref}>
      {props.children}
    </div>
  );
}
import {useToolbar} from 'react-aria';
import {useRef} from 'react';

// Reuse the Button from your component library. See below for details.
import {Button} from 'your-component-library';

function Toolbar(props) {
  let ref = useRef(null);
  // Get props for the toolbar element
  let { toolbarProps } =
    useToolbar(
      props,
      ref
    );

  return (
    <div
      {...toolbarProps}
      ref={ref}
    >
      {props.children}
    </div>
  );
}

Now we can render a simple toolbar with actionable items:

<Toolbar aria-label="Actions">
  <Button>Copy</Button>
  <Button>Cut</Button>
  <Button>Paste</Button>
</Toolbar>
<Toolbar aria-label="Actions">
  <Button>Copy</Button>
  <Button>Cut</Button>
  <Button>Paste</Button>
</Toolbar>
<Toolbar aria-label="Actions">
  <Button>Copy</Button>
  <Button>Cut</Button>
  <Button>
    Paste
  </Button>
</Toolbar>
Show CSS
[role=toolbar] {
  --separator-color: var(--spectrum-global-color-gray-500);
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  padding: 15px;
  border: 1px solid var(--separator-color);
}
[role=toolbar] {
  --separator-color: var(--spectrum-global-color-gray-500);
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  padding: 15px;
  border: 1px solid var(--separator-color);
}
[role=toolbar] {
  --separator-color: var(--spectrum-global-color-gray-500);
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  padding: 15px;
  border: 1px solid var(--separator-color);
}

Button#

The Button component is used in the above example as an interactive child. It is built using the useButton hook, and can be shared with many other components.

Show code
import {useButton} from 'react-aria';

function Button(props) {
  let { children } = props;
  let ref = useRef();
  let { buttonProps, isPressed } = useButton({
    ...props,
    elementType: 'span'
  }, ref);

  return (
    <span
      {...buttonProps}
      style={{
        background: isPressed ? 'darkgreen' : 'green',
        color: 'white',
        padding: 10,
        cursor: 'pointer',
        userSelect: 'none',
        WebkitUserSelect: 'none'
      }}
      ref={ref}
    >
      {children}
    </span>
  );
}
import {useButton} from 'react-aria';

function Button(props) {
  let { children } = props;
  let ref = useRef();
  let { buttonProps, isPressed } = useButton({
    ...props,
    elementType: 'span'
  }, ref);

  return (
    <span
      {...buttonProps}
      style={{
        background: isPressed ? 'darkgreen' : 'green',
        color: 'white',
        padding: 10,
        cursor: 'pointer',
        userSelect: 'none',
        WebkitUserSelect: 'none'
      }}
      ref={ref}
    >
      {children}
    </span>
  );
}
import {useButton} from 'react-aria';

function Button(props) {
  let { children } =
    props;
  let ref = useRef();
  let {
    buttonProps,
    isPressed
  } = useButton({
    ...props,
    elementType: 'span'
  }, ref);

  return (
    <span
      {...buttonProps}
      style={{
        background:
          isPressed
            ? 'darkgreen'
            : 'green',
        color: 'white',
        padding: 10,
        cursor:
          'pointer',
        userSelect:
          'none',
        WebkitUserSelect:
          'none'
      }}
      ref={ref}
    >
      {children}
    </span>
  );
}

Internationalization#


You are responsible for localizing all labels, both for the toolbar itself as well as all the content that is passed into the toolbar.

RTL#

In right-to-left languages, the toolbar should be mirrored both at the toolbar level as well as inside groups as appropriate. Ensure that your CSS accounts for this.