Mover 
About
Mover lets focus move within a container using the arrow keys (plus Home/End/PageUp/PageDown), instead of requiring a Tab press per item.
<div data-tabster='{"mover": {}}'>
<button>Button1</button>
<button>Button2</button>
<button>Button3</button>
</div>
Normally reaching Button3 from Button1 takes two Tab presses. With Mover
enabled, arrow keys move between the buttons, and a single Tab press moves
focus out of the whole container (unless tabbable is set — see below).
Mover plays well with Groupper: a common pattern is a Mover list whose items are each a Groupper, so arrow keys move between items and Enter/Escape moves into/out of an item's own focusable content.
Setup
Call getMover() once to enable the mover data-tabster key:
import { createTabster, getMover } from "tabster";
const tabster = createTabster(window);
getMover(tabster);
Properties
interface MoverProps {
direction?: MoverDirection;
memorizeCurrent?: boolean;
tabbable?: boolean;
cyclic?: boolean;
trackState?: boolean;
visibilityAware?: Visibility;
hasDefault?: boolean;
visibilityTolerance?: number;
}
direction
Both | Vertical | Horizontal | Grid | GridLinear
The default, Both, moves focus to the previous/next focusable element for
either Up/Left or Down/Right presses. Vertical only responds to Up/Down,
Horizontal only to Left/Right.
Grid moves focus to the visually adjacent item based on layout (useful for
a grid of cards or table cells) — arrow keys don't wrap between rows.
GridLinear behaves like Grid but additionally allows linear movement:
pressing Right past the last item of a row continues onto the first item of
the next row (and Left/wrap the other way).
import {
createTabster,
getMover,
getTabsterAttribute,
MoverDirections,
} from "tabster";
const tabster = createTabster(window);
getMover(tabster);
<div
{...getTabsterAttribute({
mover: { direction: MoverDirections.Grid },
})}
>
{/* grid items */}
</div>;
memorizeCurrent
When Tabbing into the Mover from outside, focus normally lands on the first
element (or last, if Tabbing backwards). With memorizeCurrent: true,
Tabster remembers the last element you interacted with inside the Mover and
returns focus there instead, if it's still available.
tabbable
By default, pressing Tab while inside a Mover moves focus out of the Mover
entirely (so you can Tab past a long or infinite list in one press). Set
tabbable: true to let both Tab and the arrow keys move within the Mover.
cyclic
By default, pressing an arrow key on the last item does nothing further.
With cyclic: true, it wraps around to the first item (and vice versa).
trackState
When set, Mover tracks each item's visibility and dispatches a
tabster:mover:state custom event with that state
({ isCurrent, visibility }) whenever it changes. Only enable this when you
actually consume the event — tracking visibility for every item has a real
performance cost, especially for long lists.
visibilityAware
Invisible | PartiallyVisible | Visible
By default, Tabbing into a Mover from outside focuses the first rendered
focusable element, which can force a virtualized list to scroll and load
more items just to reach it. visibilityAware changes that to focus the
first element that is actually visible (at or above the given visibility
level) instead. Implicitly enables trackState.
hasDefault
Defaults to true. When enabled, Mover prioritizes an element marked
focusable: { isDefault: true } (see Focusable element
properties) as the element to focus
when entering from outside.
visibilityTolerance
A number between 0 and 1 (default 0.8) controlling how much of an
element must remain vertically visible when Page Up or Page Down searches for
its destination. For example, an element that's 10% clipped by its scroll
container still qualifies at the default tolerance.
Custom navigation
Mover's key handling is replaceable one key at a time. Set
focusable.ignoreKeydown on an element
or ancestor to stop Tabster from handling selected keys there, then use your
own input or application state to dispatch:
MoverMoveFocusEventto ask the containing Mover to perform a movement command using its normal direction, visibility, and boundary rules.MoverMemorizedElementEventto replace or clear the item used bymemorizeCurrent.
MoverStateEvent also exposes current-item and visibility changes when
trackState is enabled. Together, these
Mover events support custom key maps, command
surfaces, and controlled selection models without reimplementing Mover's
focus traversal.
For Mover's built-in keyboard handling, Tabster also dispatches
tabster:movefocus before applying the proposed
focus change. Preventing that event cancels the move, allowing a listener to
substitute a different destination while leaving Mover's behavior unchanged
for all other cases.