Member Junction
    Preparing search index...

    mjTabList — the ARIA tabs keyboard contract, shared by every MJ tab strip.

    Applied to the element that holds the tabs. It manages the things the APG tabs pattern requires and that hand-rolled strips almost always miss:

    • roving tabindex — exactly ONE tab is in the page tab order at a time (the selected one), so Tab moves past the whole strip rather than through every tab in it;
    • arrow-key navigation — Left/Right move between tabs and activate, Home/End jump to the ends, wrapping at the edges;
    • Enter / Space activate the focused tab;
    • Delete / Backspace request closure of the focused tab, which is the APG answer for closeable tabs — a close button inside a tab cannot be its own tab stop without putting two stops per tab in the page order.

    MJ's two strips disagree about what a tab IS: one projects <mj-tab> component instances and addresses them by positional index, the other renders a data array and addresses it by stable id. A shared base class would have to pick one of those models. This directive picks neither — it operates on the DOM, so each strip keeps its own contract and only has to agree that a tab is [role="tab"] and that the selected one carries aria-selected="true". That agreement is the accessibility requirement anyway, so nothing is invented to make the sharing work.

    Mark each tab role="tab", keep aria-selected truthful, and act on (TabActivateRequested) / (TabCloseRequested). The directive sets role="tablist" and owns tabindex — do not also bind it, or the two will fight.

    Implements

    • AfterViewInit
    • AfterViewChecked
    • OnDestroy
    Index

    Constructors

    Properties

    TabActivateRequested: EventEmitter<MJTabListRequest> = ...

    The user asked to move to / activate a tab. The host maps the index onto its own model.

    TabCloseRequested: EventEmitter<MJTabListRequest> = ...

    The user pressed Delete/Backspace on a tab. Hosts without closeable tabs simply ignore this.

    Methods

    • The primary trigger. Deliberately a lifecycle hook rather than only the MutationObserver: observer callbacks are asynchronous, so between a selection change and the flush the tab order would point at the PREVIOUS tab — and a tab with no tabindex at all is not focusable, making focus() a silent no-op. Running here keeps the tab order correct in the same frame the selection changed.

      Safe to run every cycle: it writes only when a value actually differs, so it cannot loop.

      Returns void