Skip to main content

Web Components SDK

The Web Components SDK is a wrapper around the JavaScript SDK to provide an easy to use custom element (<live-codes>), yet retaining the full power, by having access to the SDK methods.

Demo

show code
import { createPlayground } from 'livecodes';

const options = {
"config": {
"markup": {
"language": "html",
"content": "<live-codes height=\"90vh\" params='{\"console\": \"open\"}'>\n <template>\n <template lang=\"html\">\n <h1>Hello World!</h1>\n </template>\n <style lang=\"scss\">\n h1 { color: royalblue; }\n </style>\n <script lang=\"ts\" active>\n console.log('hello!');\n </script>\n </template>\n</live-codes>\n\n<script src=\"https://cdn.jsdelivr.net/npm/livecodes@undefined/web-components.js\"></script>\n"
}
}
};
createPlayground('#container', options);

Installation

Please refer to the SDK installation section.

Usage

The custom element is registered by importing livecodes/web-components.

Using a bundler

HTML
<live-codes></live-codes>

<script type="module">
import 'livecodes/web-components';
</script>

Using a CDN

Alternatively, you can load the web components SDK directly from a CDN using a script tag:

HTML
<script src="https://cdn.jsdelivr.net/npm/livecodes@undefined/web-components.js"></script>

<live-codes></live-codes>

TypeScript Support

Types are exported from livecodes/web-components for convenience:

TypeScript
import type { EmbedOptions, Playground } from 'livecodes/web-components';

The following types are available:
Code, Config, EmbedOptions, Language, Playground.

TypeScript types are documented here.

Declarative Code via Children

You can provide code for the playground declaratively using child elements inside a wrapper <template>. This avoids the need to set code in JavaScript strings and gives you full IDE syntax highlighting and autocomplete.

The outer <template> element (highlighted in the example below) ensures that inner <style> and <script> elements are inert — the browser will not execute them or apply their styles to the embedding page. The code is trimmed and dedented automatically.

Use <template>, <style>, and <script> elements with a lang attribute to set the language for each editor. These elements map to the corresponding editors (markup, style, script).

HTML
<live-codes height="400px">
<template>
<template lang="html">
<h1>Hello World</h1>
<p>Welcome to <strong>LiveCodes</strong></p>
</template>
<style lang="scss">
body {
font-family: sans-serif;
h1 { color: royalblue; }
p { font-size: 1.2em; }
}
</style>
<script lang="ts">
const btn = document.querySelector<HTMLButtonElement>('#btn');
btn?.addEventListener('click', () => {
btn.textContent = 'Clicked!';
});
</script>
</template>
</live-codes>

If the lang attribute is omitted, the defaults are html, css, and javascript.

Active Editor

Use the active boolean attribute on a code element to set the initially active editor:

HTML
<live-codes height="400px">
<template>
<template lang="html"><h1>Hello</h1></template>
<style lang="css">h1 { color: blue; }</style>
<script lang="ts" active>console.log('focused here');</script>
</template>
</live-codes>

Combining Children with Config

You can combine declarative children with config (attribute or property) and params. The merge precedence is:

  1. config property (highest — explicit programmatic override)
  2. Children (declarative defaults)
  3. config attribute (lowest — inline JSON settings)

Children are best used for code content, while the config attribute is useful for non-code settings:

HTML
<live-codes
height="400px"
config='{"processors": ["tailwindcss"]}'
params='{"console": "open"}'
>
<template>
<template lang="html">
<h1 class="text-3xl font-bold text-blue-600">Hello Tailwind</h1>
</template>
<script lang="ts">console.log('Hello!');</script>
</template>
</live-codes>

If the config property is set programmatically for the same editor, the property wins:

HTML
<live-codes id="demo" height="400px">
<template>
<template lang="html"><h1>Default from children</h1></template>
</template>
</live-codes>

<script type="module">
import 'livecodes/web-components';

const el = document.getElementById('demo');
// This overrides the children's markup content
el.config = {
markup: { language: 'html', content: '<h1>Override from JS</h1>' },
};
</script>

Reactivity

Children content is reactive. Programmatically changing the content inside the wrapper <template> will trigger a call to setConfig on the existing playground. However, updating the config property is the preferred way to change the content.

HTML
<live-codes id="demo" height="400px">
<template>
<template><h1>Hello World!</h1></template>
<style lang="css" active>h1 { color: blue; }</style>
</template>
</live-codes>

<button onclick="updateCode()">Change Color</button>

<script type="module">
import 'livecodes/web-components';

function updateCode() {
const el = document.getElementById('demo');
const wrapper = el.querySelector(':scope > template');
const style = wrapper.content.querySelector('style');
style.textContent = 'h1 { color: red; }';
}

// expose to onclick
window.updateCode = updateCode;
</script>

Attributes

The following HTML attributes are supported and correspond to embed options:

AttributeTypeDescription
app-urlstringThe URL of the LiveCodes app.
configstringA JSON string representing the config object.
importstringA resource to import.
loadingstringWhen to load the playground ("click", "lazy", or "eager").
paramsstringA JSON string representing URL Query parameters.
templatestringA starter template to load.
headlessbooleanWhether to use the headless mode of LiveCodes.
heightstringSets the height of playground container element.
data-default-stylesstringIf set to "false", disables the default styles applied to the playground container.

Example:

HTML
<live-codes template="react" loading="click"></live-codes>

<script type="module">
import 'livecodes/web-components';
</script>

Default Styles

By default, the <live-codes> element is styled when the playground is initialized (including height, border, etc.). To disable default styles, set the data-default-styles attribute to "false".

HTML
<live-codes data-default-styles="false" class="custom"></live-codes>

<script type="module">
import 'livecodes/web-components';
</script>

Properties

For complex values it is recommended to use JavaScript properties on the element.

  • config

    Type: object | string.

    The config object for the playground or the URL of the config file.

    Example:

    HTML
    <live-codes></live-codes>

    <script type="module">
    import 'livecodes/web-components';

    const playground = document.querySelector('live-codes');
    playground.config = {
    markup: {
    language: 'markdown',
    content: '# Hello World!',
    },
    };
    </script>
  • params

    Type: object.

    An object that represents URL Query parameters.

    Example:

    HTML
    <live-codes></live-codes>

    <script type="module">
    import 'livecodes/web-components';

    const playground = document.querySelector('live-codes');
    playground.params = {
    html: '<h1>Hello World!</h1>',
    css: 'h1 {color: blue;}',
    };
    </script>
  • sdk

    Type: Playground | undefined (read-only).

    The playground SDK instance. Available after the playground has been initialized. This allows making use of the full capability of the SDK by calling SDK methods.

    Example:

    HTML
    <live-codes></live-codes>

    <script type="module">
    import 'livecodes/web-components';

    const playground = document.querySelector('live-codes');
    playground.addEventListener('sdkready', async () => {
    const code = await playground.sdk.getCode();
    console.log(code);
    });
    </script>

Events

  • sdkready

    Fired when the SDK is ready. The SDK instance is available via event.detail.sdk or via the sdk property on the element. Use this event to access the SDK methods.

    Example:

    HTML
    <live-codes></live-codes>
    <button id="run">Run</button>

    <script type="module">
    import 'livecodes/web-components';

    let sdk;

    const playground = document.querySelector('live-codes');
    playground.config = {
    markup: {
    language: 'html',
    content: '<h1>Hello World!</h1>',
    },
    };
    playground.addEventListener('sdkready', (e) => {
    sdk = e.detail.sdk;
    });

    document.getElementById('run').addEventListener('click', async () => {
    await sdk?.run();
    });
    </script>

Reactive Attributes and Properties

Changing any attribute or property will cause the playground to reload with the new options. However, changing the config property is an exception — it updates the playground in place using the SDK method setConfig, without triggering a full reload. This allows for a smooth update experience when only the configuration changes.

Similarly, changing the height attribute and children content also update the playground in place without triggering a full reload.

Example:

HTML
<live-codes></live-codes>
<button id="switch">Switch to Markdown</button>

<script type="module">
import 'livecodes/web-components';

const playground = document.querySelector('live-codes');
playground.config = {
markup: {
language: 'html',
content: '<h1>Hello World!</h1>',
},
};

document.getElementById('switch').addEventListener('click', () => {
playground.config = {
markup: {
language: 'markdown',
content: '# Hello World! (from Markdown)',
},
};
});
</script>

Methods

  • destroy()

    Destroys the playground instance and cleans up resources. This is also called automatically when the element is removed from the DOM.

    Example:

    HTML
    <live-codes></live-codes>
    <button id="destroy">Destroy</button>

    <script type="module">
    import 'livecodes/web-components';

    const playground = document.querySelector('live-codes');
    document.getElementById('destroy').addEventListener('click', () => {
    playground.destroy();
    });
    </script>

Storybook

See storybook for usage examples.