The LiveCodes SDK provides a native Vue 3 component for embedding playgrounds in Vue applications.
Installation
Install the livecodes package:
Import
Import the Vue component:
<script setup>
import LiveCodes from 'livecodes/vue';
</script>
For TypeScript users:
<script setup lang="ts">
import LiveCodes from 'livecodes/vue';
import type { Props } from 'livecodes/vue';
</script>
Basic Usage
<script setup>
import LiveCodes from 'livecodes/vue';
const config = {
markup: {
language: 'html',
content: '<h1>Hello from Vue!</h1>',
},
};
</script>
<template>
<LiveCodes :config="config" />
</template>
Props
The Vue component accepts all EmbedOptions as props, plus Vue-specific props.
Component-Specific Props
Height of the playground container.<LiveCodes height="600px" />
Embed Options Props
appUrl
string
default:"https://livecodes.io"
URL of the LiveCodes app.
Configuration object or URL to config JSON.<LiveCodes :config="config" />
Resource to import (GitHub, GitLab, gist, etc.).<LiveCodes import="https://github.com/username/repo" />
Load in headless mode.<LiveCodes :headless="true" />
loading
'lazy' | 'click' | 'eager'
default:"lazy"
Loading strategy.<LiveCodes loading="eager" />
URL query parameters.<LiveCodes :params="{ title: 'My Project' }" />
Starter template to load.<LiveCodes template="vue" />
Events
sdkReady
Emitted when the playground initializes. Receives the Playground SDK instance.
<script setup>
import { ref } from 'vue';
import LiveCodes from 'livecodes/vue';
const playground = ref(null);
const handleSdkReady = (sdk) => {
playground.value = sdk;
console.log('Playground ready!', sdk);
};
</script>
<template>
<LiveCodes
template="javascript"
@sdk-ready="handleSdkReady"
/>
</template>
Examples
With Template
<script setup>
import LiveCodes from 'livecodes/vue';
</script>
<template>
<LiveCodes template="vue" />
</template>
With Custom Config
<script setup>
import LiveCodes from 'livecodes/vue';
const config = {
markup: {
language: 'markdown',
content: '# Hello World\n\nThis is a **LiveCodes** playground in Vue.',
},
style: {
language: 'css',
content: 'body { font-family: system-ui; padding: 2rem; }',
},
script: {
language: 'javascript',
content: 'console.log("Hello from JavaScript!");',
},
autoupdate: true,
};
</script>
<template>
<LiveCodes
:config="config"
height="500px"
class="my-playground"
/>
</template>
<style scoped>
.my-playground {
border: 2px solid #42b883;
border-radius: 8px;
}
</style>
Interactive Controls
<script setup>
import { ref } from 'vue';
import LiveCodes from 'livecodes/vue';
const playground = ref(null);
const handleRun = async () => {
await playground.value?.run();
};
const handleFormat = async () => {
await playground.value?.format();
};
const handleGetCode = async () => {
const code = await playground.value?.getCode();
console.log('Current code:', code);
};
</script>
<template>
<div>
<div class="controls">
<button @click="handleRun">Run</button>
<button @click="handleFormat">Format</button>
<button @click="handleGetCode">Get Code</button>
</div>
<LiveCodes
template="javascript"
height="400px"
@sdk-ready="(sdk) => playground = sdk"
/>
</div>
</template>
<style scoped>
.controls {
margin-bottom: 1rem;
display: flex;
gap: 0.5rem;
}
button {
padding: 0.5rem 1rem;
border: 1px solid #42b883;
background: white;
color: #42b883;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #42b883;
color: white;
}
</style>
Watching Events
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import LiveCodes from 'livecodes/vue';
const playground = ref(null);
const logs = ref([]);
let watchers = [];
const handleSdkReady = (sdk) => {
playground.value = sdk;
// Watch console output
const consoleWatcher = sdk.watch('console', ({ method, args }) => {
logs.value.push({ method, args, timestamp: Date.now() });
});
// Watch code changes
const codeWatcher = sdk.watch('code', ({ code }) => {
console.log('Code changed:', code.script.content);
});
watchers = [consoleWatcher, codeWatcher];
};
onUnmounted(() => {
watchers.forEach(w => w.remove());
});
</script>
<template>
<div>
<LiveCodes
template="javascript"
height="300px"
@sdk-ready="handleSdkReady"
/>
<div class="console-output">
<h3>Console Output:</h3>
<ul>
<li v-for="(log, i) in logs" :key="i">
{{ log.method }}: {{ JSON.stringify(log.args) }}
</li>
</ul>
</div>
</div>
</template>
<style scoped>
.console-output {
margin-top: 1rem;
padding: 1rem;
background: #f5f5f5;
border-radius: 4px;
}
</style>
Reactive Config
<script setup>
import { ref, computed } from 'vue';
import LiveCodes from 'livecodes/vue';
const language = ref('javascript');
const code = ref('console.log("Hello!");');
const config = computed(() => ({
script: {
language: language.value,
content: code.value,
},
autoupdate: true,
}));
</script>
<template>
<div>
<div class="controls">
<select v-model="language">
<option value="javascript">JavaScript</option>
<option value="typescript">TypeScript</option>
<option value="python">Python</option>
</select>
<textarea v-model="code" rows="3" />
</div>
<LiveCodes :config="config" height="400px" />
</div>
</template>
<style scoped>
.controls {
margin-bottom: 1rem;
}
textarea {
width: 100%;
padding: 0.5rem;
font-family: monospace;
margin-top: 0.5rem;
}
</style>
Loading from Config URL
<script setup>
import LiveCodes from 'livecodes/vue';
const configUrl = 'https://example.com/playground-config.json';
</script>
<template>
<LiveCodes :config="configUrl" height="500px" />
</template>
Multiple Playgrounds
<script setup>
import LiveCodes from 'livecodes/vue';
</script>
<template>
<div class="playgrounds">
<div class="playground">
<h2>React Example</h2>
<LiveCodes template="react" height="400px" />
</div>
<div class="playground">
<h2>Vue Example</h2>
<LiveCodes template="vue" height="400px" />
</div>
</div>
</template>
<style scoped>
.playgrounds {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
gap: 2rem;
}
.playground h2 {
margin-bottom: 1rem;
}
</style>
Composition API Example
<script setup>
import { ref, watch } from 'vue';
import LiveCodes from 'livecodes/vue';
const playground = ref(null);
const shareUrl = ref('');
const currentCode = ref('');
const generateShareUrl = async () => {
if (!playground.value) return;
shareUrl.value = await playground.value.getShareUrl();
};
const updateCodeDisplay = async () => {
if (!playground.value) return;
const code = await playground.value.getCode();
currentCode.value = code.script.content;
};
const handleSdkReady = (sdk) => {
playground.value = sdk;
// Watch for code changes
sdk.watch('code', () => {
updateCodeDisplay();
});
};
</script>
<template>
<div>
<LiveCodes
template="javascript"
height="300px"
@sdk-ready="handleSdkReady"
/>
<div class="info">
<button @click="generateShareUrl">Generate Share URL</button>
<p v-if="shareUrl">Share URL: <a :href="shareUrl" target="_blank">{{ shareUrl }}</a></p>
<p v-if="currentCode">Current Code Length: {{ currentCode.length }} characters</p>
</div>
</div>
</template>
<style scoped>
.info {
margin-top: 1rem;
padding: 1rem;
background: #f9f9f9;
border-radius: 4px;
}
button {
margin-bottom: 1rem;
}
</style>
TypeScript Support
The component is fully typed for TypeScript:
<script setup lang="ts">
import { ref } from 'vue';
import LiveCodes from 'livecodes/vue';
import type { Props, Playground, Config } from 'livecodes/vue';
const playground = ref<Playground | null>(null);
const config: Partial<Config> = {
markup: {
language: 'html',
content: '<h1>TypeScript Support</h1>',
},
autoupdate: true,
};
const handleReady = (sdk: Playground) => {
playground.value = sdk;
};
</script>
<template>
<LiveCodes
:config="config"
height="500px"
@sdk-ready="handleReady"
/>
</template>
Styling
Style the component using scoped styles:
<script setup>
import LiveCodes from 'livecodes/vue';
</script>
<template>
<div class="playground-wrapper">
<LiveCodes
class="custom-playground"
template="vue"
height="600px"
/>
</div>
</template>
<style scoped>
.playground-wrapper {
max-width: 1200px;
margin: 2rem auto;
padding: 1rem;
}
.custom-playground {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
</style>
Component Lifecycle
The component handles lifecycle automatically:
- Mount: Creates the playground when component mounts
- Update: Updates config when props change
- Unmount: Destroys the playground and cleans up
Best Practices
-
Use refs for SDK access: Store the playground instance in a ref when you need to call methods.
-
Use computed for reactive config: Wrap config in
computed() for reactive updates.
<script setup>
import { ref, computed } from 'vue';
import LiveCodes from 'livecodes/vue';
const code = ref('console.log("Hello!");');
const config = computed(() => ({
script: { language: 'javascript', content: code.value },
}));
</script>
<template>
<LiveCodes :config="config" />
</template>
-
Clean up watchers: Remove watchers in
onUnmounted hook.
-
Set explicit height: Always specify a height for better UX.
Nuxt Integration
For Nuxt 3, use client-only component:
<template>
<ClientOnly>
<LiveCodes template="vue" />
</ClientOnly>
</template>
<script setup>
import LiveCodes from 'livecodes/vue';
</script>
Or configure in nuxt.config.ts:
export default defineNuxtConfig({
build: {
transpile: ['livecodes'],
},
});
Next Steps
Svelte Usage
Learn about using LiveCodes with Svelte
Methods
Explore available methods
Events
Understand the event system
Types
Browse TypeScript types