Skip to content

Controlling embeds with the SDK’s VM interface

INFO

These methods only apply to projects embedded on a page.

All of the embed methods of the StackBlitz JS SDK automatically connect to the embedded StackBlitz VM, giving you programmatic access to the embedded project.

Use the VM to:

  • control the UI of an embedded StackBlitz project;
  • change the currently open file(s);
  • read and write files from the project’s virtual filesystem.

Getting access to the VM

DEMO

Check this demo of using the VM:

With embed methods

The embedProject, embedProjectId, and embedGithubProject methods of the SDK return a Promise resolving to an instance of the SDK’s VM class. We recommend using await in an async function to keep track of the VM instance. For example:

js
import sdk from '@stackblitz/sdk';

async function start() {
  // Embeds a project and keeps track of the VM
  const vm = await sdk.embedProjectId('embed', 'react-ts');

  // Performs an action with VM
  const deps = await vm.getDependencies();
  await vm.applyFsDiff({
    create: {
      'hello.txt': 'Hello, this is a new file!',
      'deps.txt': JSON.stringify(deps, null, 2),
    },
    destroy: [],
  });
}

start();

With connect(iframe)

The SDK’s connect method can be used to retrieve the VM instance for an existing StackBlitz iframe.

ArgumentRequiredTypeDescription
iframeYesHTMLIframeElementAn iframe embedding a StackBlitz project.

Example:

js
import sdk from '@stackblitz/sdk';

const EMBED_ID = 'embed';

// Embeds iframe
sdk.embedProjectId(EMBED_ID, 'react-ts');

// Retrieves and uses the VM when clicking a button
document.getElementById('test-button').addEventListener('click', async () => {
  const iframe = document.getElementById(EMBED_ID);
  const vm = await sdk.connect(iframe);
  const deps = await vm.getDependencies();
  console.log(deps);
});

VM properties and methods

applyFsDiff(diff)

Updates project files. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
diffYesObjectSpecifies files to create or delete
diff.createYesObjectObject with file paths as keys and contents as values
diff.destroyYesArrayFile paths of the files to delete

INFO

When modifying existing files, the new content of the modified files must be provided in full.

Example:

js
await vm.applyFsDiff({
  create: {
    'index.js': `console.log('Hello World!')`,
    'package.json': `{ "scripts": { "start": "node index.js" } }`,
  },
  destroy: ['test.js', 'error.log'],
});

getDependencies()

Gets the project’s defined dependencies. Returns a promise resolving to a ProjectDependencies object.

In EngineBlock projects, it returns the dependencies as resolved by the built-in package manager, with exact versions as values. For example: { 'react': '18.2.0' }.

Since 1.7.0: in project running on WebContainers, it reads the contents of the top-level package.json file and returns an object merging dependencies and devDependencies, with the original version specifiers as values. For example, { 'react': '^18.0.0' }.

Example:

js
const deps = await vm.getDependencies();

if (typeof deps['vue'] === 'string') {
  console.log('Looks like a Vue.js project');
}

getFsSnapshot()

Gets a snapshot of the project files and their content. Returns a promise resolving to a ProjectFiles object.

Example:

js
const files = await vm.getFsSnapshot();
console.log(files); // { 'index.js': '…', 'package.json': '…', … }

editor.openFile(path)

Opens one or several files in tabs and/or split panes. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
pathYesOpenFileOption (String or array of strings)Path(s) of file(s) to open

Example:

js
// opens a single file
await vm.editor.openFile('src/App.css');

// opens two editor panes
await vm.editor.openFile(['README.md', 'index.js']);

editor.setCurrentFile(path)

Since 1.7.0. Experimental: exact behavior may change.

Sets a project file as the currently selected file. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
pathYesStringPath of the file to set as current
  • This may update the highlighted file in the file explorer, and the currently open and/or focused editor tab.
  • If the provided path does not match a currently open tab, a new editor tab will not open. See vm.editor.openFile to open files.

Example:

js
await vm.editor.setCurrentFile('src/App.css');

editor.setTheme(theme)

Since 1.7.0.

Changes the editor’s color theme. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
themeYesUiThemeOption (String)The color theme name.
js
await vm.editor.setTheme('light');

editor.setView(view)

Since 1.7.0.

Changes the display mode of the project. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
viewYesUiViewOption (String)The display mode name.
js
await vm.editor.setView('preview');

editor.showSidebar(visible)

Since 1.7.0.

Changes the display mode of the sidebar. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
visibleNoBooleanUse true (default) to show the sidebar, false to hide.
js
await vm.editor.showSidebar(true);

preview.origin

A string with the origin (protocol and domain) of the preview iframe. Every project created with the embedProject method gets a unique preview URL.

Because it is unknown ahead of time if the project will run a web server (and if so, on which port), vm.preview.origin will always be null in projects running on WebContainers. You can use vm.preview.getUrl instead.

Example:

js
if (vm.preview.origin) {
  console.log('Preview is running at ' + vm.preview.origin);
}

preview.getUrl()

Since 1.7.0. Experimental: exact behavior may change.

Gets the current preview URL. Returns a promise resolving to a string or to null.

The preview URL may not reflect the exact path of the current page if the user or page code has triggered a navigation within the preview iframe.

In WebContainers projects, the preview URL will be null initially, and until the project starts a web server.

Example:

js
const url = await vm.preview.getUrl();

if (url != null && url.startsWith('/about')) {
  console.log('Looks like the About page!');
}

preview.setUrl(path)

Since 1.7.0. Experimental: exact behavior may change.

Changes the path of the preview URL. Returns a promise resolving to null.

ArgumentRequiredTypeDescription
pathYesStringA URL path starting with /.

The provided path must start with / and cannot change the origin of the preview URL.

In WebContainers projects, calls to vm.preview.setUrl will be ignored if there is no web server running currently.

Example:

js
// Navigates to the About page
await vm.preview.setUrl('/about');