Groupper 
About
Groupper controls whether a set of focusable elements participates normally in Tab order or behaves as a single entry point with an explicit interaction mode.
Consider a chat message that contains a few inner buttons (reactions,
reply, ...). Without Groupper, reaching the message input below a long
conversation means Tabbing through every inner button of every message.
With a Limited Groupper on each message, a single Tab reaches (or leaves) the
whole message, and pressing Enter on the message moves focus inside it, to its
own buttons; Escape moves back out.
An element with groupper should itself be focusable (typically
tabindex={0}):
<div
data-tabster='{"groupper":{"tabbability":1}}'
tabindex="0"
title="Message actions"
>
<button>Like</button>
<button>Reply</button>
</div>
Groupper plays well with Mover — a common pattern is a Mover list whose items are each a Groupper.
Setup
Call getGroupper() once to enable the groupper data-tabster key:
import { createTabster, getGroupper } from "tabster";
const tabster = createTabster(window);
getGroupper(tabster);
Properties
interface GroupperProps {
tabbability?: GroupperTabbability;
delegated?: boolean;
}
tabbability
Unlimited | Limited | LimitedTrapFocus
With Unlimited (the default when omitted), the Groupper's inner elements
are reachable by Tab like normal — Mover still treats the whole
Groupper as one entity for arrow-key navigation, but no extra Enter press is
required to get inside it.
With Limited, an Enter press is required to move focus from the Groupper
container to its first inner focusable element (and Escape moves back out
to the container). Once inside, Tab moves between the Groupper's own
focusables; Tabbing past the last one moves focus outside the Groupper
entirely.
LimitedTrapFocus behaves like Limited, except Tab is trapped inside the
Groupper once activated — reaching the last inner focusable and pressing Tab
again wraps back to the first one instead of leaving the Groupper.
import { getTabsterAttribute, GroupperTabbabilities } from "tabster";
<div
tabIndex={0}
{...getTabsterAttribute({
groupper: { tabbability: GroupperTabbabilities.LimitedTrapFocus },
})}
>
<button>Button1</button>
<button>Button2</button>
</div>;
delegated
Fine-tunes when a Limited/LimitedTrapFocus Groupper "activates" (moves
into its inner content) for the case where the Groupper container itself
isn't focusable. By default, the Groupper activates automatically as soon as
Tab lands on the first inner focusable element. With delegated: true, it
only activates after Enter is explicitly pressed on that first inner
element — useful when the container can't carry tabindex={0} itself (for
example, a <tr> in some browsers) but should still require an explicit
"enter" gesture.
Custom navigation
Groupper's Enter and Escape handling can be replaced independently. Use
focusable.ignoreKeydown to leave
either key to your application, then dispatch a
GroupperMoveFocusEvent with GroupperMoveFocusActions.Enter or
GroupperMoveFocusActions.Escape when your own command, input method, or
application state should enter or leave the Groupper.
This programmatic event follows the same nested Groupper context as the built-in keyboard behavior, allowing custom interaction models without duplicating its focus traversal.
For built-in Enter/Escape handling, Tabster also dispatches
tabster:movefocus before changing focus.
Preventing that event cancels the proposed move, so an application can choose
another destination without replacing Groupper behavior globally.