Skip to main content

RoverProvider

An accessibility pattern for a grouped set of inputs


How to
  • Use the tab key to navigate to the Menu.
  • Then, use the ArrowUp and ArrowDown keys to go through each option.
  • Try pressing Home or End to jump right to the first or last elements on the group.
  • Press tab (or shift+tab) again to exit.

Development Instructions

1. Wrap each roving tabindex group in a RoverProvider

You can nest roving tabindex components in other DOM elements or React components.

<RoverProvider>
{..content here}
</RoverProvider>

You can also choose the direction of the navigation. It can either be "vertical" (default) or "horizontal".

<RoverProvider direction="horizontal">
{..content here}
</RoverProvider>

Choosing between "vertical" and "horizontal" implies you can use:

  • horizontal - "ArrowLeft" and "ArrowRight" keys
  • vertical - "ArrowUp" and "ArrowDown"
  • Home key to go to the first element
  • End key to go to the last element

2. Wrap each focusable element

For composition, try to identify which elements are the ones that are going to be affected by the RoverProvider. For each one of those, wrap them with your own component and use the useRover and useFocus hooks.

const MenuButton = ({ disabled = false, children }) => {
const buttonRef = useRef(null);

const [tabIndex, focused, handleKeyDown, handleClick] = useRover(buttonRef, disabled);

useFocus(focused, buttonRef);

function onKeyDown(event) {
handleKeyDown(event);
yourOwnFunctionToDoWhatever(event);
}

function onClick(event) {
handleClick(event);
yourOwnFunctionToDoWhatever(event);
}

return (
<button
ref={ref}
type="button"
tabIndex={tabIndex}
disabled={disabled}
onKeyDown={handleKeyDown}
onClick={onClick}
>
{children}
</button>
);
};

3. Place them inside your RoverProvider structure

Since RovingTabIndex relies on React Context, there's no need to have the buttons all as direct children of the provider. You can nest as deep as you'd like and it will work as well 🙂

<RoverProvider direction="horizontal">
<MenuButton>First Button</MenuButton>
<MenuButton disabled>Second Button</MenuButton>
<ul>
<li><MenuButton>Another Button</MenuButton>
<li><MenuButton>Another Button</MenuButton>
<li><MenuButton>Another Button</MenuButton>
<li><MenuButton>Another Button</MenuButton>
</ul>
</RoverProvider>

Differences with Focus Manager

Both are made to deal with focus and navigation but do it in different ways and for different scenarios:

  1. The FocusManager can, if necessary, scope the focus inside a group and allows the user to press the tab key to move to the next "tabbable" element (or shift+tab to move to the previous).

    💡 Tip: Use it for dealing with interface elements that require focus control, like popovers, modals and side menus.


  1. The RoverProvider can also manage focus inside a group but, instead of using the tab key to move back and forth between elements, it uses navigation keys (ArrowUp, ArrowDown, ArrowLeft or ArrowRight) to do that.

    It also makes the other group's elements unable to receive focus using the tab key since it applies the negative tabindex to the components that are not currently selected.

    💡 Tip: Use it for dealing with interface elements that require selection, like a custom select element or a navigation menu. (Still, you should try to use the native HTML elements).

Props

Rover Provider