Skip to content

Mount Coras in your framework

This guide shows how to mount Coras Embed in your framework and tear it down cleanly. Every framework uses the same SDK contract from @coras-io/embed, so the only thing that changes per framework is which lifecycle hook calls each method.

  • Install @coras-io/embed.
  • Have your distributor ID and API URL ready for config.

Map these four steps onto your framework’s component lifecycle:

  1. Get a container DOM element.
  2. Call mount({ container, page, config, params }) when the component attaches. Keep the returned CorasApp.
  3. Call app.update({ ... }) when page, params, or config change.
  4. Call app.unmount() when the component detaches.

There are two ways to lay Coras out, and they call for opposite CSS:

  • Standalone - Coras is the site. Use chrome: "managed" so the mount renders the Coras navbar and footer, and let it own the whole viewport.
  • Embedded - Coras mounts into an app that already has its own navbar, footer, and routing. Use chrome: false and treat the mount as one content region among many.

Coras renders a complete page - navbar, page content, and footer - into the container. Let it fill the viewport; do not wrap it in a centered, max-width, or text-aligned container, and remove any starter-template CSS (a centered #root/#app, demo :root colour variables, App.css) - that is the usual cause of clipped content and off-brand colours.

A minimal full-bleed reset is all you need (swap #app for your container’s selector):

html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
}
#app {
flex: 1 0 auto;
display: flex;
flex-direction: column;
}

That is the whole of it. The mount is a flex column that grows, and so is the page inside it, so the managed footer sits at the bottom of a short page on its own. You never need a rule that names a Coras element: those names are internal and can change without a major version.

If your framework wrapper puts an element of its own between that container and the mount - a React <div ref={containerRef} />, say - give it display: contents so the mount stays a direct flex child:

<div ref={containerRef} style={{ display: "contents" }} />

To mount Coras inside an existing app, set chrome: false so it renders the page alone, without the Coras navbar or footer, and keep the host’s own chrome around it. Mount into a content region - the host route’s <main>, say - and do not apply the full-bleed reset above: the mount should size to its region, not take the viewport.

Scope Coras to its own part of the host’s routes with the URL strategy’s basePath (for example basePath: "/tickets"), so buildCorasUrl and parseCorasUrl carry that prefix and the host’s other routes are left untouched. See the embedded example for a full host app.

Each tab is copy-paste ready and produces the same runtime behavior. The examples mount on attach and tear down on detach; to react to changing page, params, or config, also call app.update({ ... }) from your framework’s reactive hook (step 3 above).

import { mount } from "@coras-io/embed";
const app = mount({
container: document.querySelector("#coras"),
page: "landing",
config: {
apiUrl: "https://api.coras.io",
distributorId: "your-distributor-id",
assetsUrl: "https://assets.sandbox.coras.io/shared",
locale: "en-IE",
currency: "EUR"
}
});
// Tear down when you are done:
// app.unmount();

The tabs above mount on attach and tear down on detach. When page, params, or config change while the component stays mounted, call app.update({ ... }) from your framework’s reactive hook instead of remounting. It updates in place unless page changes:

// e.g. React useEffect([id]), Vue watch, Svelte $effect, Angular ngOnChanges
appRef.current?.update({ page: "details", params: { id } });

Page elements need the DOM, so render the embed in a client-only boundary:

Framework Client-only boundary
Next.js "use client" directive
Nuxt <ClientOnly>
SvelteKit onMount
Astro client:only
  • Nothing renders and an error is thrown. mount() validates config and params before it renders anything. Invalid input throws CorasValidationError. Check the error message for the failing key.
  • The embed mounts twice in React development. With React StrictMode, double-mount effects run mount() twice. unmount() is idempotent and safe, and the second mount replaces the first.
  • Two embeds on one page interfere. They do not. The SDK scopes theme, chrome, and events to each mount root, so multiple embeds coexist without leakage.
  • Icons are missing, the brand looks unstyled, or the page is clipped. Pass strict: true (or wire a logger) and check the console: mount() warns when assetsUrl is unreachable, config.theme has no colours, or a managed-chrome page is constrained by an ancestor. Each points at the fix.
  • Drive page changes from the host URL: see Routing for the URL loop that pairs with onNavigate and onStateChange.
  • Handle events emitted by the embed.