Headless Mode
The LiveCodes SDK can be used to create playgrounds in headless mode. In this mode, no visible output is displayed in the embedding web page. However, all SDK methods are accessible (e.g. for updating code, getting compiled code, console output, result HTML, shareable URLs, formatting code, running tests, etc).
This provides the power of leveraging the wide range of features and language support offered by LiveCodes, while retaining full control over the UI.
Usage
To create a headless playground, set the embed option view
to "headless"
.
Please note that in headless mode, the first parameter (container
) of the function createPlayground
is optional and can be omitted.
Example:
import { createPlayground } from 'livecodes';
createPlayground({
view: 'headless',
config: {
markup: {
language: 'markdown',
content: '# Hello World!',
},
},
}).then(async (playground) => {
const code = await playground.getCode();
console.log(code.markup.compiled); // "<h1>Hello World!</h1>"
console.log(code.result); // (result page HTML)
});
Examples
The following examples show how to use the headless mode to make a Markdown editor, an MDX editor and a Python interpreter.
You may want to view the following playgrounds in full screen (using the full screen button in the top right of each playground).
Markdown Editor
In this demo, code changes are watched using the SDK method watch('code', callback)
. The callback function accepts an argument which is an object with the properties code
and config
(see getCode
and getConfig
). The compiled code is obtained as code.markup.compiled
.
show code
- JS
- TS
- React
- Vue
- Svelte
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = \"# Hello, LiveCodes!\\n\\n\";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"markdown\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import { createPlayground, type EmbedOptions } from 'livecodes';
const options: EmbedOptions = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = \"# Hello, LiveCodes!\\n\\n\";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"markdown\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import LiveCodes from 'livecodes/react';
export default function App() {
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = \"# Hello, LiveCodes!\\n\\n\";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"markdown\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
return (<LiveCodes {...options}></LiveCodes>);
}
<script setup>
import LiveCodes from "livecodes/vue";
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = \"# Hello, LiveCodes!\\n\\n\";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"markdown\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
</script>
<template>
<LiveCodes v-bind="options" />
</template>
<script>
import { onMount } from 'svelte';
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = \"# Hello, LiveCodes!\\n\\n\";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"markdown\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
let container;
onMount(() => {
createPlayground(container, options);
});
</script>
<div bind:this="{container}"></div>
MDX Editor
In this demo, code changes are watched using the SDK method watch('code', callback)
. The callback function accepts an argument which is an object with the properties code
and config
(see getCode
and getConfig
). The result HTML is obtained as code.result
.
If you do not want to run the result page in the headless playground and only want to get the generated result HTML, you can set the configuration option `autoupdate to false
.
show code
- JS
- TS
- React
- Vue
- Svelte
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n <h1>Hello, {name}!</h1>\n <p>You clicked {count} times.</p>\n <button onClick={() => setCount(count + 1)}>Click me</button>\n </>\n );\n};\n\n<Hello name=\"LiveCodes\"></Hello>\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from [mdxjs.com](https://mdxjs.com/)\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"mdx\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import { createPlayground, type EmbedOptions } from 'livecodes';
const options: EmbedOptions = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n <h1>Hello, {name}!</h1>\n <p>You clicked {count} times.</p>\n <button onClick={() => setCount(count + 1)}>Click me</button>\n </>\n );\n};\n\n<Hello name=\"LiveCodes\"></Hello>\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from [mdxjs.com](https://mdxjs.com/)\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"mdx\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import LiveCodes from 'livecodes/react';
export default function App() {
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n <h1>Hello, {name}!</h1>\n <p>You clicked {count} times.</p>\n <button onClick={() => setCount(count + 1)}>Click me</button>\n </>\n );\n};\n\n<Hello name=\"LiveCodes\"></Hello>\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from [mdxjs.com](https://mdxjs.com/)\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"mdx\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
return (<LiveCodes {...options}></LiveCodes>);
}
<script setup>
import LiveCodes from "livecodes/vue";
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n <h1>Hello, {name}!</h1>\n <p>You clicked {count} times.</p>\n <button onClick={() => setCount(count + 1)}>Click me</button>\n </>\n );\n};\n\n<Hello name=\"LiveCodes\"></Hello>\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from [mdxjs.com](https://mdxjs.com/)\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"mdx\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
</script>
<template>
<LiveCodes v-bind="options" />
</template>
<script>
import { onMount } from 'svelte';
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none;\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n <h1>Hello, {name}!</h1>\n <p>You clicked {count} times.</p>\n <button onClick={() => setCount(count + 1)}>Click me</button>\n </>\n );\n};\n\n<Hello name=\"LiveCodes\"></Hello>\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from [mdxjs.com](https://mdxjs.com/)\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"markdown\",\n });\n editor.setSize(\"100%\", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: \"mdx\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(compile, 1000));\n livecodes.watch(\"code\", ({ code, config }) => {\n createSandbox(document.querySelector(\"#output\"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement(\"iframe\");\n iframe.src = \"https://livecodes-sandbox.pages.dev/v7/\";\n iframe.sandbox =\n \"allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts\";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, \"*\");\n };\n container.innerHTML = \"\";\n container.appendChild(iframe);\n return iframe;\n };\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/markdown/markdown.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
let container;
onMount(() => {
createPlayground(container, options);
});
</script>
<div bind:this="{container}"></div>
Python Interpreter
In this demo, console output is obtained using the SDK method watch('code', callback)
. The callback function accepts an argument which is an object with the properties method
and args
indicating the console method and the arguments that were passed (as an array).
show code
- JS
- TS
- React
- Vue
- Svelte
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `def say_hello(name):\n return f\"Hello, {name}!\"\n\nprint(say_hello(\"LiveCodes\"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"python\",\n });\n editor.setSize(\"100%\", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: \"python\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(run, 1000));\n livecodes.watch(\"console\", ({ method, args }) => {\n const output = document.querySelector(\"#output\");\n output.innerHTML = args.join(\"\\n\");\n if (method === \"error\") {\n output.style.color = \"red\";\n } else {\n output.style.color = \"unset\";\n }\n });\n\n await run();\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/python/python.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n margin: 1em;\n white-space: pre;\n font-family: monospace;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import { createPlayground, type EmbedOptions } from 'livecodes';
const options: EmbedOptions = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `def say_hello(name):\n return f\"Hello, {name}!\"\n\nprint(say_hello(\"LiveCodes\"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"python\",\n });\n editor.setSize(\"100%\", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: \"python\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(run, 1000));\n livecodes.watch(\"console\", ({ method, args }) => {\n const output = document.querySelector(\"#output\");\n output.innerHTML = args.join(\"\\n\");\n if (method === \"error\") {\n output.style.color = \"red\";\n } else {\n output.style.color = \"unset\";\n }\n });\n\n await run();\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/python/python.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n margin: 1em;\n white-space: pre;\n font-family: monospace;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
createPlayground('#container', options);
import LiveCodes from 'livecodes/react';
export default function App() {
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/[email protected]\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `def say_hello(name):\n return f\"Hello, {name}!\"\n\nprint(say_hello(\"LiveCodes\"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"python\",\n });\n editor.setSize(\"100%\", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: \"python\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(run, 1000));\n livecodes.watch(\"console\", ({ method, args }) => {\n const output = document.querySelector(\"#output\");\n output.innerHTML = args.join(\"\\n\");\n if (method === \"error\") {\n output.style.color = \"red\";\n } else {\n output.style.color = \"unset\";\n }\n });\n\n await run();\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/python/python.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n margin: 1em;\n white-space: pre;\n font-family: monospace;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
return (<LiveCodes {...options}></LiveCodes>);
}
<script setup>
import LiveCodes from "livecodes/vue";
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `def say_hello(name):\n return f\"Hello, {name}!\"\n\nprint(say_hello(\"LiveCodes\"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"python\",\n });\n editor.setSize(\"100%\", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: \"python\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(run, 1000));\n livecodes.watch(\"console\", ({ method, args }) => {\n const output = document.querySelector(\"#output\");\n output.innerHTML = args.join(\"\\n\");\n if (method === \"error\") {\n output.style.color = \"red\";\n } else {\n output.style.color = \"unset\";\n }\n });\n\n await run();\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/python/python.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n margin: 1em;\n white-space: pre;\n font-family: monospace;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
</script>
<template>
<LiveCodes v-bind="options" />
</template>
<script>
import { onMount } from 'svelte';
import { createPlayground } from 'livecodes';
const options = {
"config": {
"markup": {
"language": "html",
"content": "<textarea id=\"editor\" style=\"display: none\"></textarea>\n<div id=\"output\">Loading...</div>\n\n<script type=\"module\">\n import { createPlayground } from \"https://cdn.jsdelivr.net/npm/livecodes@0.2.0\";\n import debounce from \"https://jspm.dev/debounce\";\n\n const initialCode = `def say_hello(name):\n return f\"Hello, {name}!\"\n\nprint(say_hello(\"LiveCodes\"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById(\"editor\"), {\n lineNumbers: true,\n mode: \"python\",\n });\n editor.setSize(\"100%\", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: \"headless\",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: \"python\",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on(\"change\", debounce(run, 1000));\n livecodes.watch(\"console\", ({ method, args }) => {\n const output = document.querySelector(\"#output\");\n output.innerHTML = args.join(\"\\n\");\n if (method === \"error\") {\n output.style.color = \"red\";\n } else {\n output.style.color = \"unset\";\n }\n });\n\n await run();\n</script>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/lib/codemirror.css\" />\n<script src=\"https://unpkg.com/[email protected]/lib/codemirror.js\"></script>\n<script src=\"https://unpkg.com/[email protected]/mode/python/python.js\"></script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n margin: 1em;\n white-space: pre;\n font-family: monospace;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n"
}
}
};
let container;
onMount(() => {
createPlayground(container, options);
});
</script>
<div bind:this="{container}"></div>