Beta Preview

Creating a pointer-friendly submenu experience

We are excited to announce support of submenus in the latest release of React Spectrum and React Aria! In the process of adding this feature, we found ourselves solving some unique challenges while working to make submenus user-friendly and accessible across an array of devices and input types. In doing so, we wanted to share our thought process in solving one of the challenges we faced along the way.

The Shortest Path

Submenus (or nested menus) enable multi-level exploration of menus, and even with a large number of options, users should be able to quickly find their desired option. A user should be able to hover over an item to see its submenu. Then, they should be able to move their pointer directly to any item in the newly opened submenu, following the shortest path. While doing so, the pointer may leave the original item entirely and hover an unrelated item in its path towards the submenu, causing the submenu to close. We need a way to know when they're moving their pointer to that submenu, so we can keep it open until they reach the submenu.

More ActionsOption 3Option 2Option 1

Predicting User Intent

We can predict the user's intent by tracking:

  • Pointer movement direction
  • Pointer movement speed

We can do this by listening for pointermove events and analyzing the changes in the pointer's position (also called delta).

Valid Movements

Imagine two lines: one from the pointer to the top of the submenu, and one from the pointer to the bottom of the submenu. We now have an area where the user might move their pointer on its path to the submenu. Any movement outside of this range should be considered invalid and should close the submenu.

More ActionsOption 5Option 4Option 3Option 2Option 1Submenu Option 3Submenu Option 4Submenu Option 5Submenu Option 2Submenu Option 1 Θ = atan2(y,x)(x,y) ΘtopΘbottomΘpointer