Skip to main content

Cross-Origin

About

Iframes are isolated from each other for eventing purposes: pressing Tab in one iframe doesn't tell any other iframe (or the host page) anything. The Cross-Origin module bridges a limited, specific set of Tabster concerns across iframe boundaries — most notably keyboard-navigation state and the Observed Element API — using postMessage under the hood.

This is an advanced, comparatively rare feature: only set it up if your application actually spans multiple frames/windows and needs focus coordination between them.

Setup

Call getCrossOrigin() in every window/frame that should participate, then call .setup() on the returned API to actually start listening for messages:

import { createTabster, getCrossOrigin } from "tabster";

const tabster = createTabster(window);
const crossOrigin = getCrossOrigin(tabster);
crossOrigin.setup();

getCrossOrigin() lazily initializes Deloser, Modalizer, Mover, Groupper, Outline, and Observed Element for you — you don't need to call their get*() functions yourself first.

By default, setup() wires a frame to automatically forward messages to its window.parent via postMessage. On the outermost window (the one with no further parent to forward to, or where you want to take over message routing yourself), you can pass a custom sender, or null to disable the default forwarding:

function setup(
sendUp?: Types.CrossOriginTransactionSend | null
): (msg: Types.CrossOriginMessage) => void;

setup() returns a message handler; wire it up to whatever transport you're forwarding cross-origin messages over if you're not relying on the default postMessage-to-parent behaviour.

API

interface CrossOriginAPI {
focusedElement: CrossOriginFocusedElementState;
observedElement: CrossOriginObservedElementState;
setup(
sendUp?: CrossOriginTransactionSend | null
): (msg: CrossOriginMessage) => void;
isSetUp(): boolean;
dispose(): void;
}

observedElement

Mirrors getObservedElement(), but resolves across frames — elements are located and focused by name no matter which participating frame they live in:

// From any participating frame:
crossOrigin.observedElement.requestFocus("myButton", 5000).then((focused) => {
console.log("Focused across frames:", focused);
});

observedElement.getElement() and waitElement() resolve asynchronously to CrossOriginElements instead of plain HTMLElements. requestFocus() resolves to a boolean indicating whether focus was moved.

focusedElement

Lets you focus an element in another frame, either by direct CrossOriginElement reference (obtained via observedElement) or by id:

crossOrigin.focusedElement.focusById("some-element-id", "root-id");

You can also subscribe() to focusedElement to track focus as it moves among elements in the participating frames.

Examples

See the "Target in Iframe" Observed Element story in Storybook for a working cross-origin requestFocus() example, and the CrossOrigin test suite in the repository for lower-level usage.