DocsPut a demo on a page
Docs

Put a demo on a page

Install a published Rendemo demo on your site with one script tag: finding the demo id, inline or a Watch-the-demo button, framework wrappers, and what to check when it does not appear.

The tag

A published demo goes on a page with one script tag. The script mounts the demo where the tag sits.

html
<script src="https://www.rendemo.com/embed.js" data-demo="acme/onboarding" async></script>

That is the whole install. Two demos on a page are two tags, and both mount. Every option on this page is another data-* attribute on that same tag.

Writing the element yourself

When the tag cannot sit where the demo belongs — a React layout, a slot in a template — load the script once and place the element yourself. src is an alias for demo, and every data-* above is the same attribute without the prefix.

html
<script src="https://www.rendemo.com/embed.js" async></script>
<rendemo-demo src="acme/onboarding"></rendemo-demo>

Finding the demo id

data-demo takes either form, and both resolve to a real, publicly servable, framable route:

  • workspace/slug — the readable one, resolving to /site/<workspace>/<slug>. This is what publishing gives you.
  • a demo UUID, resolving to /d/<id>. Stable across renames.

The demo has to be published first. Publishing is what makes it world-visible at those routes; an unpublished project has nothing for the element to load, and the element renders a fallback link rather than silently showing nothing.

Inline, or a button

Inline is the default: the demo sits in the page at a 16:10 box, showing a poster still until the visitor starts it. Nothing but the poster image loads until then.

html
<!-- in the page -->
<script src="https://www.rendemo.com/embed.js" data-demo="acme/onboarding" async></script>

<!-- behind a "Watch the demo" button -->
<script src="https://www.rendemo.com/embed.js" data-demo="acme/onboarding" data-mode="modal" async></script>

Modal mode builds a real dialog, not a styled <div>: a focus trap that survives focus walking into the cross-document iframe, Escape closing from inside the demo as well as outside, scroll lock, and focus restored to whatever opened it.

The host owns whether it is open. Toggle the open attribute, and listen for rendemo:close to clear it — the element deliberately does not close itself, because your button’s state is yours to own. Ratio, poster behaviour and the full attribute list are in Reference.

React, Vue, Svelte

The element is a custom element, so it works in any framework without a package. What differs is where the script tag goes and whether you want a typed wrapper around it.

rendemo_get_embed({ projectId, framework, mode }) returns all of it for a published demo: the script tag and where it goes for that framework, the snippet, and wrapper source for next-app-router, next-pages, react, vue or svelte. It fails with a clear message rather than emitting a snippet for a demo that is not published yet.

A wrapper may do exactly two things

Forward props to attributes, and bridge the five events to callbacks. Anything else belongs in embed.js, which can be fixed for every site at once — a wrapper lives in your repo, where it cannot. Rendemo’s own site wrapper obeys the same rule.

When it does not appear

The element never fails silently: it renders a link to the demo instead. Three causes.

  1. 1

    A strict Content Security Policy

    A script-src on the host page must allow https://www.rendemo.com. Without it the element never upgrades and the fallback link is what renders.
  2. 2

    The demo is not published

    Nothing is servable at the resolved route yet. Publish it, then reload — no code change.
  3. 3

    The demo is password-protected

    These cannot be embedded today, and the reason is not fixable from your side. See below.

Password-protected demos cannot be embedded

When the visitor submits the password, the framed page issues its access cookie as SameSite=Lax with no Partitioned attribute. Inside the third-party iframe the embed creates, that is a third-party cookie, and browsers that enforce partitioning defaults — most of them now — drop it on write. The password check succeeds, the redirect fires, the cookie never lands, and the visitor is back on the password form.

There is no workaround at the embed layer. Link to the demo directly instead — /d/<id> or /site/<workspace>/<slug> in a new tab — where the cookie is first-party and works normally.