Skip to main content
Destroys the playground instance and removes all event listeners. After calling this method, any further SDK method calls will throw an error. This method is useful for cleaning up resources when the playground is no longer needed, such as when removing it from the page or navigating away.

Signature

playground.destroy(): Promise<void>

Parameters

None.

Returns

Promise<void>
Promise<void>
A promise that resolves when the playground has been destroyed. If called when already destroyed, the promise rejects with an error message.

Usage

Basic Usage

import { createPlayground } from "livecodes";

const playground = await createPlayground("#container");

// Use the playground...
await playground.run();

// Later, when done:
await playground.destroy();
// Playground is now destroyed
// Container is cleared
// Event listeners are removed

// This will throw an error:
// await playground.run(); // Error: Cannot call API methods after calling `destroy()`.

Clean Up on Page Navigation

import { createPlayground } from "livecodes";

let playground;

async function initPlayground() {
  playground = await createPlayground("#container");
}

// Clean up when leaving the page
window.addEventListener('beforeunload', async () => {
  if (playground) {
    await playground.destroy();
  }
});

Destroy and Recreate

import { createPlayground } from "livecodes";

let playground = await createPlayground("#container", {
  config: {
    markup: {
      language: "html",
      content: "<h1>Version 1</h1>",
    },
  },
});

// Later, completely reset the playground
const resetButton = document.getElementById('reset');

resetButton.addEventListener('click', async () => {
  // Destroy the old playground
  await playground.destroy();
  
  // Create a fresh one
  playground = await createPlayground("#container", {
    config: {
      markup: {
        language: "html",
        content: "<h1>Fresh Start</h1>",
      },
    },
  });
});

Multiple Playgrounds

import { createPlayground } from "livecodes";

const playgrounds = [];

// Create multiple playgrounds
for (let i = 1; i <= 3; i++) {
  const playground = await createPlayground(`#container${i}`);
  playgrounds.push(playground);
}

// Later, destroy all playgrounds
async function cleanupAll() {
  for (const playground of playgrounds) {
    await playground.destroy();
  }
  playgrounds.length = 0; // Clear the array
}

// Call cleanup when needed
await cleanupAll();

Tab Navigation with Cleanup

import { createPlayground } from "livecodes";

const tabs = {
  editor: null,
  preview: null,
  settings: null,
};

async function showTab(tabName) {
  // Destroy current playground if exists
  if (tabs[tabName]) {
    await tabs[tabName].destroy();
  }
  
  // Create new playground for this tab
  tabs[tabName] = await createPlayground(`#${tabName}-container`);
}

// Switch tabs
document.getElementById('editor-tab').addEventListener('click', () => {
  showTab('editor');
});

document.getElementById('preview-tab').addEventListener('click', () => {
  showTab('preview');
});

With Watch Cleanup

import { createPlayground } from "livecodes";

const playground = await createPlayground("#container");

// Set up watchers
const codeWatcher = playground.watch('code', ({ code }) => {
  console.log('Code changed');
});

const consoleWatcher = playground.watch('console', ({ method, args }) => {
  console[method](...args);
});

// Later, clean up everything
async function cleanup() {
  // Remove watchers (optional - destroy() will handle this)
  codeWatcher.remove();
  consoleWatcher.remove();
  
  // Destroy playground
  await playground.destroy();
}

await cleanup();

Error Handling

import { createPlayground } from "livecodes";

const playground = await createPlayground("#container");

await playground.destroy();

// Attempting to use destroyed playground
try {
  await playground.run();
} catch (error) {
  console.error(error);
  // Error: "Cannot call API methods after calling `destroy()`."
}

// Attempting to destroy again
try {
  await playground.destroy();
} catch (error) {
  console.error(error);
  // Error: "Cannot call API methods after calling `destroy()`."
}

Watch Destroy Event

import { createPlayground } from "livecodes";

const playground = await createPlayground("#container");

// Watch for destruction
playground.watch('destroy', () => {
  console.log('Playground destroyed!');
  // Clean up any external resources
  // Update UI state
  document.getElementById('status').textContent = 'Playground destroyed';
});

// Later
await playground.destroy();
// "Playground destroyed!" is logged

Memory Leak Prevention

import { createPlayground } from "livecodes";

class PlaygroundManager {
  constructor() {
    this.playground = null;
  }
  
  async init(container) {
    // Clean up old playground if exists
    await this.cleanup();
    
    // Create new playground
    this.playground = await createPlayground(container);
  }
  
  async cleanup() {
    if (this.playground) {
      await this.playground.destroy();
      this.playground = null;
    }
  }
}

const manager = new PlaygroundManager();

// Initialize
await manager.init('#container');

// Later, when component unmounts or page changes
await manager.cleanup();

React Component Example

import { createPlayground, type Playground } from "livecodes";
import { useEffect, useRef } from "react";

function PlaygroundComponent() {
  const containerRef = useRef<HTMLDivElement>(null);
  const playgroundRef = useRef<Playground | null>(null);
  
  useEffect(() => {
    let mounted = true;
    
    async function init() {
      if (containerRef.current) {
        const playground = await createPlayground(containerRef.current);
        
        if (mounted) {
          playgroundRef.current = playground;
        } else {
          // Component unmounted during creation, clean up
          await playground.destroy();
        }
      }
    }
    
    init();
    
    // Cleanup on unmount
    return () => {
      mounted = false;
      
      if (playgroundRef.current) {
        playgroundRef.current.destroy();
      }
    };
  }, []);
  
  return <div ref={containerRef} />;
}

What Gets Cleaned Up

When destroy() is called, the following cleanup occurs:
  1. iframe removal - The playground iframe is removed from the DOM
  2. Event listeners - All message event listeners are removed
  3. Watchers - All watch callbacks are cleared
  4. Observers - Intersection observers (for lazy loading) are disconnected
  5. State - Internal state is marked as destroyed

Notes

  • After calling destroy(), the playground object cannot be reused. You must create a new playground instance.
  • All watchers are automatically removed when the playground is destroyed.
  • The container element remains in the DOM but is emptied of the playground content.
  • Calling destroy() multiple times will result in an error.
  • This method should be called when:
    • Removing the playground from the page
    • Navigating away from a single-page application route
    • Switching between different playground configurations
    • Preventing memory leaks in long-running applications
  • watch() - Watch for the "destroy" event
  • All SDK methods will throw an error after destroy() is called

Build docs developers (and LLMs) love