Codelet logoCodelet

Getting started

The five-minute path from install to a workbench or editor on screen, in TypeScript, React or Vue

This page mounts a workbench, mounts a standalone editor, covers the React and Vue wrappers, adds one extension, and renders either on a server. Read Introduction first if you haven't — it covers installing codelet and what each package entry gives you.

#Mount a workbench

A workbench is a file tree, tabs, a command palette and a panel, backed by an in-memory FileSystem.

import { FileSystem, Workbench } from "codelet/workbench";

const workbench = new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/README.md": "# Hello\n\nEdit me." }),
});
Read more in Guide > Workbench.

#Mount an editor

Editor is a single code field. Construct one with the element to mount into; everything else is optional.

import { Editor } from "codelet";

const editor = new Editor({
  parent: document.getElementById("editor")!,
  doc: "console.log('hello')\n",
  lang: "ts",
});

editor.value reads the current document. Call editor.destroy() when the element is removed, to tear the view down.

Read more in Guide > Workbench#the Standalone Editor.

#React and Vue

import { CodeEditor } from "codelet/react";

function Example() {
  return (
    <CodeEditor
      initialValue={"console.log('hello')\n"}
      lang="ts"
      onChange={(value) => console.log(value)}
      style={{ height: 300 }}
    />
  );
}

initialValue mounts uncontrolled: codelet owns the document from then on, and edits are reported through onChange. Pass value instead for a controlled editor, kept in sync with state on every render. onCreate hands you the underlying Editor once it exists, and className/style reach the wrapping <div> (style is merged over the wrapper's own positioning).

<script setup lang="ts">
import { CodeEditor } from "codelet/vue";
</script>

<template>
  <CodeEditor
    initial-value="console.log('hello')\n"
    lang="ts"
    style="height: 300px"
    @change="(value) => console.log(value)"
  />
</template>

The same initialValue/value split applies: initialValue for an uncontrolled editor, value (or v-model:value) for one kept in sync with state. class and style fall through to the wrapping element automatically. In place of onChange and onCreate props, the component emits change (the value and the CodeMirror update) and create (the Editor instance).

Both wrappers also accept lang, theme and readOnly, and update the live editor whenever those props change.

Read more in Guide > Workbench#the Standalone Editor.

#Adding an extension

A workbench with no extensions has no Search icon, no terminal, nothing beyond the built-in explorer, tabs and command palette. Pass extensions to add them:

import { search } from "codelet/extensions/search";
import { FileSystem, Workbench } from "codelet/workbench";

const workbench = new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/README.md": "# Hello" }),
  extensions: [search],
});

That adds a Search icon to the activity bar, backed by codelet/extensions/search. Every built-in extension is its own package entry, so a workbench only pays for the ones it imports.

Read more in Guide > Extensions.
Read more in Extensions.

#Server rendering

renderEditorHTML (from codelet) and renderWorkbench (from codelet/workbench/server) return static markup — a stand-in editor or a full shell — rendered without CodeMirror ever running. The client mounts Editor or Workbench over the same element and takes over from there:

import { FileSystem } from "codelet/workbench";
import { renderWorkbench } from "codelet/workbench/server";

export default {
  fetch() {
    const shell = renderWorkbench({
      fs: new FileSystem({ "/README.md": "# Hello\n\nEdit me." }),
      open: "/README.md",
    });
    return new Response(
      `<!doctype html><div id="app">${shell}</div><script type="module" src="/client.js"></script>`,
      { headers: { "content-type": "text/html;charset=utf-8" } },
    );
  },
};

Workbench hydrates automatically when parent already has children, and mounts fresh otherwise, so the same client code works for a server-rendered page or a client-only one.

Warning

open, active, view, panel, secondary, theme, extensions and themes are markup. Pass the exact same values to renderWorkbench() on the server and to Workbench on the client, or hydration has nothing to match and the shell rebuilds instead of taking over.

renderEditorHTML is the same idea for a standalone editor:

import { renderEditorHTML } from "codelet";

const html = renderEditorHTML({ doc: "console.log('hello')\n", lang: "ts" });
Read more in Guide > Workbench.
Read more in Guide > Workbench#the Standalone Editor.

#No CSS to import

codelet ships no CSS file. Every rule is inline, so mounting the editor or the workbench is one import, with nothing to add to a stylesheet or a build pipeline.

Read more in Guide > Files.
Read more in Guide > Themes.
Read more in Guide > Server.