Events & JS API
window.Ocheso. Use it to hear what players do, and to mount, theme and steer widgets from your own code. None of it is needed for a plain embed.Events
Each event reaches you three ways: Ocheso.on for every widget, widget.on for one, and a bubbling DOM event ocheso:<name> whose detail also carries the widget.
| Event | Detail | When |
|---|---|---|
| ready | {} | The frame has loaded and is showing. |
| resize | { height } | The content changed height; the widget has already followed it. |
| join | { tournament, status } | The player entered. status is approved, or pending when the organiser approves entries. |
| gameStart | { id, color } | The signed-in player's game began. |
| gameEnd | { id, result, termination, color } | Their game finished. result is white, black or draw; color is theirs. |
| identityRequired | { reason } | Someone needs to sign in with your login: join, my-game, expired or login. |
| error | { code, message } | blocked (no answer in 10 s), identity (your fetchToken failed) or proto (a loader too old). |
// Every widget on the page:
Ocheso.on("join", (detail, widget) => {
analytics.track("tournament_join", { tournament: detail.tournament });
});
// One widget:
const off = widget.on("gameEnd", (detail) => showResult(detail.result));
off(); // stop listening
// Or as DOM events, which bubble from the widget's element:
document.addEventListener("ocheso:identityRequired", (e) => {
if (e.detail.reason === "login") openMyLoginModal();
});- 19:02:11 ocheso:ready {}
- 19:02:11 ocheso:resize {"height":612}
- 19:02:40 ocheso:identityRequired {"reason":"join"}
- 19:03:05 ocheso:join {"tournament":"weekly-blitz","status":"approved"}
- 19:05:00 ocheso:gameStart {"id":"5f0c…","color":"white"}
- 19:11:42 ocheso:gameEnd {"id":"5f0c…","result":"white","termination":"checkmate","color":"white"}
window.Ocheso
| Member | What it does |
|---|---|
| version | The loader's version, e.g. "1.0.0". |
| ready(fn) | Calls fn(Ocheso) once the page has loaded and every snippet is mounted. |
| mount(el, options) | Turns an element (or a selector) into a widget and returns it; null if the options name nothing valid. |
| identify(fetchToken, options) | Signs your users in. See Player sign-in. |
| logout() | Forgets the player in every widget. Call it when your user signs out. |
| setTheme(theme | null) | Themes every widget on the page; null goes back to the snippets' own. |
| on(event, fn) | Listens to every widget. Returns a function that stops it. |
| scan(root?) | Mounts snippets under root now, instead of waiting for the page to change. |
| widgets() | The widgets on the page. |
A widget
| Member | What it does |
|---|---|
| el · iframe | The element it was mounted on, and the iframe inside it. |
| ready | A promise that settles when the frame is up. |
| on(event, fn) | Listens to this widget only. |
| setTheme(theme | null) | Themes this widget, over the page's theme. |
| navigate(view, params?) | Switches view, e.g. navigate("pairings", { round: 2 }). |
| unmount() | Removes the frame and gives the element back as it was. |
Mounting from code
mount takes the same settings as the data-attributes, camelCased: tournament, org, series, game, view, theme, lang, accent, radius, font, board, height, minHeight, lazy, title, limit, round, mobileFullscreen, sounds, compact, header.
const widget = Ocheso.mount("#tournament", {
tournament: "weekly-blitz",
view: "standings",
theme: "dark",
limit: 10,
});
await widget.ready; // the frame is up and showing
widget.navigate("pairings", { round: 2 });
widget.setTheme({ accent: "#e4572e" });
widget.unmount(); // the element is left as it wasIn a React component
"use client";
import { useEffect, useRef } from "react";
// For when a component should own its widget. Needs the loader (or the queue
// stub below) on the page. Plain markup plus the script works too: the loader
// mounts and unmounts elements as React renders them.
export function Standings({ slug }: { slug: string }) {
const el = useRef<HTMLDivElement>(null);
useEffect(() => {
let widget: Ocheso.Widget | null = null;
window.Ocheso?.ready((api) => {
widget = el.current && api.mount(el.current, { tournament: slug, view: "standings" });
});
return () => widget?.unmount();
}, [slug]);
return <div ref={el} />;
}Calling before the script loads
The loader is async, so your code may run first. Paste this queue stub above your own script and calls wait in line until the loader arrives; it replays them in order. A queued call returns nothing, so code that needs the widget back goes through Ocheso.ready.
<script>!function(w){var o=w.Ocheso=w.Ocheso||{q:[]};["ready","mount","identify","logout","setTheme","on","scan"].forEach(function(m){o[m]=o[m]||function(){o.q.push([m,arguments])}})}(window)</script>TypeScript
Types for all of the above are published at /embed/v1.d.ts. Save it into your project (for example as types/ocheso.d.ts) and window.Ocheso, the options and every event detail are typed.
Single-page apps
- Load the script once, in your app shell. A second copy notices the first and does nothing.
- Snippets added or removed by your router are mounted and cleaned up by the loader. Frameworks that keep pages alive while hidden (keep-alive caches, Turbo's page cache) keep their widgets too: call
widget.unmount()when you leave such a page. - Listeners added with
Ocheso.onlive as long as the page; keep the function it returns to remove them.