High quality interactions that work across a wide variety of devices are essential to a great user experience. React Aria implements hooks for cross-device interactions that ensure consistent behavior across browsers and platforms.
Building high quality interactions that work across a wide variety of devices and platforms is very difficult today. The web runs across an extremely wide variety of devices and platforms: desktop, mobile, TVs, cars, even refrigerators. This extends to interaction models too: the web supports mouse, touch, keyboard, gamepads, screen readers, and more.
Unfortunately, the web platform doesn't have any high level abstractions across these interaction models. There's no high level gesture events, or even the concept of a “press” event that works across all of these interaction models. We just have low level events like mouse, touch, keyboard, and focus events, and it's up to developers to put them together properly. This leads to many web apps not working consistently across various types of devices and interaction models.
React Aria includes a collection of Hooks that provide higher level abstractions over the low level events exposed by the web platform, and helps normalize the behavior across browsers and devices. This includes support for high level events like “press”, “hover”, and “focus”. Some of these seem simple at first, but you’d be surprised how complicated it is to handle these events in a cross-browser, cross-device way. There are many tiny behavioral differences that have a big impact on how well components work across all of these platforms.
The web was originally designed for mouse events. Later, when touch devices were introduced, browsers added support for touch events. However, since existing web apps had not been designed with touch in mind, browsers needed to emulate mouse events on touch devices to ensure some compatibility with them.
Touch input is quite different than mouse input though. For example, it is possible to hover over an element with a mouse,
but not with touch. But since existing apps designed for mouse input have hover only effects, browsers emulate hover events
on touch devices. Touching an element once fires
onMouseEnter and touching it again fires
onMouseLeave. On one hand this is
good because it means the functionality is accessible to users on touch devices, but on the other hand, it's not a great experience.
Mobile browsers also support many types of gestures by default, e.g. double tap to zoom, scrolling, and long press to select text.
Because of this, touch devices often delay firing events like
onClick in order to first determine if the user intends to zoom or
scroll the page. In the context of a highly interactive web application, this leads to a sub-optimal user experience.
The new pointer events spec helps simplify handling events across mouse, touch, and stylus/pen interaction models. React Aria uses pointer events where available with fallbacks on older devices to mouse and touch events. It normalizes many cross-browser behavioral differences, and ensures that all browsers and platforms behave consistently. In addition, React Aria supports additional interaction models like keyboard and focus events to ensure that all users can interact with your app, not just mouse and touchscreen users.
CSS pseudo classes like
:active are also problematic in many cases, especially on hybrid devices that support
both mouse and touch. They also emulate mouse behavior on touch devices, e.g. showing hover effects when you touch elements.
See usePress and useHover for more details about React Aria's hooks for cross device interactions.
Keyboard and focus behavior#
Keyboard and focus support is important to allow users to navigate your app with a keyboard. This is imperative for users who are unable to physically use a mouse or touch screen, but also nice for power users who may find it faster to navigate parts of your app without lifting their hands from the keyboard.
At a high level, keyboard navigation is broken up into tab stops, which may be navigated by pressing the Tab key to move to the next tab stop, and Shift + Tab to move to the previous tab stop. A tab stop may be an atomic component like a text field or button, or a composite component like a listbox, radio group, grid, or toolbar. Composite components behave as a single tab stop. Elements within a composite component are typically navigated with the arrow keys, while the Tab key continues to navigate to the next/previous tab stop. React Aria implements hooks for many of these composite components and handles all of the keyboard navigation behavior for elements inside them.
Overlay elements like dialogs, popovers, and menus have additional focus behavior to ensure that focus stays within them while they are open, and focus is restored back to the element that opened them when they are closed. In React Aria this is implemented by the FocusScope component.
Another important feature for keyboard users is a focus ring. This is a visual affordance for the currently focused element, which allows a keyboard user to know which element they are currently on. It should only be visible when navigating with a keyboard, so as not to distract mouse and touchscreen users. This can be implemented using the useFocusRing hook or the FocusRing component. The useFocusVisible hook can also be used to determine whether the user is currently navigating with a keyboard or not.
React Aria is careful to handle events fired by assistive technology, and normalizes this behavior as needed so it is consistent
with other interactions. For example, while we use pointer events for mouse and touch interactions, many screen readers do not
fire these events at all, instead only firing
onClick. React Aria handles this and simulates press start and press end events
so that components receive a consistent stream of events regardless of the interaction model.
Supported browsers and platforms#
All React Aria components are tested across a wide variety of browsers and devices. We test across devices with mouse input, touchscreens, and also hybrid devices.
- Chrome 88+ on macOS and Windows
- Firefox 85+ on macOS and Windows
- Safari 13+ on macOS
- Edge 88+ on Windows
- Safari 13+ on iOS and iPadOS
- Chrome 88+ on Android