Horizontal lists
Navigate a horizontal list or toolbar with the Left and Right arrow keys, with defaults that follow the text direction in right-to-left layouts.
Set data-keyrove-orientation="horizontal" on a list's root to use
←/→. In left-to-right text, → moves to the next item and ← to the
previous one. ↑/↓ keep their browser behavior.
<div id="filters" data-keyrove-orientation="horizontal">
<button data-keyrove-item tabindex="0">All</button>
<button data-keyrove-item tabindex="0">Unread</button>
<button data-keyrove-item tabindex="0">Starred</button>
<button data-keyrove-item tabindex="0">Snoozed</button>
<button data-keyrove-item tabindex="0">Drafts</button>
</div>
import { keyRove } from '@mixedrays/keyrove';
document
.querySelector('#filters')
.addEventListener('keydown', (e) => keyRove(e));
Home/End still jump to the ends, PageUp/PageDown still move a page, and Tab
keeps its default behavior. Moves follow DOM order. Lists are vertical unless
the orientation is set to the literal value horizontal.
Right to left
Under dir="rtl", the defaults reverse: ← is next and → is previous.
This keeps navigation aligned with items laid out in right-to-left order.
<div id="filters-rtl" dir="rtl" data-keyrove-orientation="horizontal">
<button data-keyrove-item tabindex="0">الكل</button>
<button data-keyrove-item tabindex="0">غير المقروءة</button>
<button data-keyrove-item tabindex="0">المميّزة بنجمة</button>
<button data-keyrove-item tabindex="0">المؤجلة</button>
<button data-keyrove-item tabindex="0">المسودات</button>
</div>
Compare the readouts: → reports next in the first bar and prev in the RTL
bar. The action names describe movement through DOM order.
The direction comes from the nearest dir attribute at or above the root, and
otherwise from the computed style, so a dir on <html> is enough for every
group on the page. Like every other attribute it is read on the keypress, so a
page that switches language switches its arrows with it. The
API reference has the resolution rules.
Explicit keys stay literal
An explicit data-keyrove-next-key or data-keyrove-prev-key wins over the
orientation, and it is never flipped: it names a physical key and means that
key in either direction.
<!-- Right is next and Left is previous, in LTR and in RTL alike -->
<div data-keyrove-next-key="ArrowRight" data-keyrove-prev-key="ArrowLeft">
…
</div>
Use orientation for arrows that follow text direction. Use explicit bindings for fixed keys; see custom keys.
Grids
A grid needs no orientation. Its next and prev moves already run along the
row, on the reading-direction arrows, and its row moves take
↑ ↓. The attribute is ignored
once data-keyrove-cols is above 1; see grid, and
its right-to-left section for how
the cell arrows flip.
Wrapping a strip
Add data-keyrove-loop to wrap next/previous at the ends. Under RTL, ←
wraps forward. See looping lists for entry
behavior and the moves that do not wrap.
Telling users about it
keyrove reads its own attribute, not aria-orientation. A role="toolbar" or
role="tablist" is horizontal by default in ARIA, so nothing more is needed
there; a role="listbox" or role="menu" laid out sideways should carry
aria-orientation="horizontal" alongside, so assistive technology announces
the arrows the group actually answers to.