Skip to content

Handle events and callbacks

The embed reports what happens inside it through a small, typed event contract. Use it to route navigation, sync URL state, and react to reservations, payments, and errors.

Every event is delivered two ways:

  • A mount() callback, for example onNavigate. Use callbacks for normal integrations.
  • A DOM CustomEvent named coras:<name>, dispatched from the mounted container. Use addEventListener only for advanced cases, such as delegating to existing listeners.

Both carry the same detail payload.

Event Callback When it fires
coras:ready onReady The page mounted and the first render is ready.
coras:navigate onNavigate The embed requests navigation. The host should route.
coras:state-change onStateChange In-page state changed, such as filters or selection.
coras:reservation-created onReservationCreated A reservation was created.
coras:payment-status onPaymentStatus Payment status changed.
coras:error onError A safe, redacted error occurred.

Pass callbacks to mount(). Each receives the event detail directly.

import { mount } from "@coras-io/embed";
const app = mount({
container,
page: "landing",
config,
onReady({ page }) {
// page: "landing" | "search" | "details" | "payment" | "help" | "suggestion-widget"
},
onNavigate(intent) {
// intent: { page, params?, locale?, currency?, href?, source }
router.navigate(intent);
},
onStateChange(state) {
// state: { page, params, locale?, currency? }
},
onReservationCreated({ reservationId, expiresIn, ticketDeliveryMethod }) {
// all three fields are optional
},
onPaymentStatus({ status, reference }) {
// status: "succeeded" | "failed" | "pending"
// reference is an optional public reference, never a provider secret
},
onError({ code, message, page }) {
// code: stable machine code, e.g. "invalid_page_params"
},
});

coras:navigate and coras:state-change look similar but have different jobs. Keep them separate to avoid router loops.

  • coras:navigate is a request to navigate: a cross-page action such as opening details or running a search, or an external link. The host maps the intent to its router and calls app.update().
  • coras:state-change reports in-page state such as filters or selection. The host decides whether to persist this state in the URL.

For the full pattern, see Routing.

Listen on the same container you passed to mount(). The detail payload matches the callback argument.

container.addEventListener("coras:navigate", (event) => {
console.log(event.detail.page, event.detail.source);
});

When a page has multiple mounts, each event and callback reaches only its own instance.

onObservability reports per-mount lifecycle and diagnostic facts, separate from the coras:* host events. Names are dot-namespaced, for example coras.page-loaded, coras.unmounted, and coras.error.

mount({
container,
page: "landing",
config,
onObservability(event) {
// event: { name, page?, data? }
},
});

The events emitted today, with the keys they carry in data:

Name When it fires data keys
coras.page-loaded A page finished its first render. { page }
coras.error A redacted error was reported. { code }
coras.unmounted The mount was torn down. None.

Treat name and data as an open set: more events and keys can be added. data values are limited to strings, numbers, booleans, and null.