Code Editor

Monaco-based code editor with syntax highlighting, multi-tab editing, command palette, JSON schema validation, and full programmatic control.

Live Demo

<iframe id="ce-demo" src="/online/webapp/code-editor" width="100%" height="450" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('ce-demo', 'ceSocket');</script>

Embed

<iframe src="https://sgapps.io/online/webapp/code-editor"
    width="100%" height="600" frameborder="0" allow="clipboard-write"></iframe>

Events Reference


active-file:codeEditor:value -- Get or Set Editor Content

The most commonly used event. When called with a string, it sets the editor text. When called with only a callback, it returns the current text.

Arg Type Description
value string (optional) New content to set
callback function (err, value: string) when getting, (err) when setting

// Set content
socket.fire("webapp::instance::request",
    "active-file:codeEditor:value",
    "function hello() {\n    return 'world';\n}",
    function (err) { console.log(err || "Content set"); }
);

// Get content
socket.fire("webapp::instance::request",
    "active-file:codeEditor:value",
    function (err, value) {
        if (err) return console.error(err);
        console.log("Content:", value);
    }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:value','// Hello from the docs page!\nfunction greet(name) {\n return 'Hello, ' + name + '!';\n}\n\nconsole.log(greet('World'));',function(err){if(err)alert('Set error: '+err.message)})">Try: Set JS Code</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:value',function(err,v){if(err)return alert('Get error: '+err.message);alert('Length: '+v.length+' chars\n\nFirst 200 chars:\n'+v.substring(0,200))})">Try: Get Code</button>


active-file:codeEditor:syntax -- Get or Set Language Mode

Changes the syntax highlighting language. Uses Monaco's language identifiers: javascript, typescript, html, css, json, python, markdown, xml, sql, yaml, go, rust, cpp, etc.

Arg Type Description
syntax string (optional) Language ID to set
callback function (err, currentLanguage: string)

// Set to Python
socket.fire("webapp::instance::request", "active-file:codeEditor:syntax", "python");

// Get current language
socket.fire("webapp::instance::request", "active-file:codeEditor:syntax",
    function (err, lang) { console.log("Language:", lang); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:syntax','javascript')">Try: JavaScript</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:syntax','python')">Try: Python</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:syntax','html')">Try: HTML</button>


active-file:codeEditor:options -- Set Monaco Editor Options

Configures the Monaco editor instance. Any Monaco IEditorOptions can be passed.

Arg Type Description
options object Monaco editor options
callback function (err)

// Make read-only with large font
socket.fire("webapp::instance::request", "active-file:codeEditor:options", {
    readOnly: true,
    fontSize: 18,
    wordWrap: "on",
    minimap: { enabled: false }
});

// Restore editable
socket.fire("webapp::instance::request", "active-file:codeEditor:options", {
    readOnly: false,
    fontSize: 14
});

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:options',{readOnly:true,fontSize:18})">Try: Read-Only + Large Font</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:options',{readOnly:false,fontSize:14})">Try: Restore Editable</button>


active-file:codeEditor:selection -- Get Selected Text

Returns the current text selection with line/column positions.

socket.fire("webapp::instance::request", "active-file:codeEditor:selection",
    function (err, sel) {
        console.log("Selected:", sel);
        // { startLine: 3, startCol: 5, endLine: 3, endCol: 20, text: "selected text" }
    }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:selection',function(e,s){alert(s.text?('Selected: "'+s.text+'" at line '+s.startLine):'No selection')})">Try: Get Selection</button>


active-file:codeEditor:insertText -- Insert Text

Inserts text at a specific position or at the current cursor position. If a position object is provided, text is inserted at that line/column. Otherwise, it replaces the current selection.

Arg Type Description
text string Text to insert
position object (optional) &#x7B; line: number, col: number &#x7D;
callback function (err)

// Insert at line 1, column 1
socket.fire("webapp::instance::request", "active-file:codeEditor:insertText",
    "// Auto-generated header\n",
    { line: 1, col: 1 }
);

// Insert at current cursor position
socket.fire("webapp::instance::request", "active-file:codeEditor:insertText",
    "console.log('inserted');"
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:insertText','// Inserted from docs!\n',{line:1,col:1})">Try: Insert at Top</button>


active-file:codeEditor:revealLine -- Scroll to Line

Scrolls the editor to center a specific line number in the viewport. Useful when navigating to errors or search results.

Arg Type Description
lineNumber number Line to reveal
callback function (err)

socket.fire("webapp::instance::request", "active-file:codeEditor:revealLine", 42);

active-file:codeEditor:json:schema -- JSON Schema Validation

Sets a JSON Schema for real-time validation of the active editor content. Monaco will show errors/warnings inline when the content doesn't match the schema.

Arg Type Description
schema object JSON Schema object
callback function (err)

socket.fire("webapp::instance::request", "active-file:codeEditor:json:schema", {
    type: "object",
    properties: {
        name: { type: "string" },
        version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" }
    },
    required: ["name", "version"]
});

active-file:save -- Save Active File

Triggers the save action on the currently active file tab. The file is written back to its original path in the file system.

socket.fire("webapp::instance::request", "active-file:save", function (err) {
    console.log(err || "File saved");
});

active-file:markers -- Set Error/Warning Markers

Programmatically set diagnostic markers (errors, warnings, info) on the editor. This is useful for showing linting results, build errors, or custom validation from your application.

Arg Type Description
markers Array Array of marker objects
callback function (err)

Each marker: &#x7B; startLine, startCol, endLine, endCol, message, severity &#x7D;
Severity levels: 1 = Hint, 2 = Info, 4 = Warning, 8 = Error

socket.fire("webapp::instance::request", "active-file:markers", [
    { startLine: 3, startCol: 1, endLine: 3, endCol: 30,
      message: "Unused variable 'x'", severity: 4 },
    { startLine: 7, startCol: 5, endLine: 7, endCol: 15,
      message: "Syntax error: unexpected token", severity: 8 }
]);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:markers',[{startLine:1,startCol:1,endLine:1,endCol:50,message:'This is a warning from the docs page',severity:4},{startLine:3,startCol:1,endLine:3,endCol:30,message:'This is an error marker',severity:8}])">Try: Set Markers</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:markers',[])">Try: Clear Markers</button>


files:open -- Open a File in a New Tab

Opens a file in a new editor tab. The type field determines the renderer: &#x22;file&#x22; for text editor, &#x22;markdown&#x22; for rendered markdown, &#x22;file-image&#x22; for image viewer.

Arg Type Description
fileConfig object &#x7B; path, type&#x3F;, title&#x3F; &#x7D;
callback function (err)

socket.fire("webapp::instance::request", "files:open", {
    path: "web:///api/applications.json",
    type: "file",
    title: "applications.json"
});

files:list -- List Open Tabs

Returns an array of all currently open tabs with their index, name, path, type, and title.

socket.fire("webapp::instance::request", "files:list", function (err, tabs) {
    console.log(tabs);
    // [{ index: 0, name: "index.js", path: "/home/user/index.js", type: "file", title: "index.js" }]
});

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','files:list',function(e,t){alert('Open tabs: '+t.length+'\n'+t.map(function(x){return x.index+': '+x.title}).join('\n'))})">Try: List Tabs</button>


files:active:set -- Activate a Tab

Switches to a specific tab by its index (as returned by files:list).

Arg Type Description
tabIndex number Zero-based tab index
callback function (err)

socket.fire("webapp::instance::request", "files:active:set", 0);

files:close:all -- Close All Tabs

Closes all open editor tabs.

socket.fire("webapp::instance::request", "files:close:all");

gui:sidebar:toggle -- Show/Hide Sidebar

Toggle the file tree sidebar visibility.

Arg Type Description
visible boolean true to show, false to hide

socket.fire("webapp::instance::request", "gui:sidebar:toggle", false); // hide
socket.fire("webapp::instance::request", "gui:sidebar:toggle", true);  // show

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','gui:sidebar:toggle',false)">Try: Hide Sidebar</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','gui:sidebar:toggle',true)">Try: Show Sidebar</button>


active-file -- Introspect the Active Tab

Returns a snapshot of the currently focused tab plus a live reference to its editor wrapper. Useful for introspection and as the entry point for building higher-level helpers (active-file:codeEditor:* handlers all go through this internally).

Arg Type Description
callback function (err, info) -- see shape below

Return shape:
Field Type Description
activeTab object &#x7B;id, name, path, type, title, statuses&#x7D; snapshot
codeEditor object \ null Monaco wrapper (.editor(), .value(), .syntax(), .isLoading(), .config()); null when no file tab is active
codeEditorConfig object \ null Convenience alias for codeEditor.config()
tab object \ null Internal Tab wrapper (full API)

socket.fire("webapp::instance::request", "active-file", function (err, info) {
    if (err) return console.error(err);
    console.log("tab id:", info.activeTab.id);
    console.log("tab path:", info.activeTab.path);
    console.log("editor ready:", info.codeEditor !== null);
});

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file',function(e,i){if(e)return alert(e.message);alert('Tab: '+(i.activeTab.title||i.activeTab.name||'(none)')+'\nPath: '+(i.activeTab.path||'(none)')+'\nType: '+i.activeTab.type+'\nEditor: '+(i.codeEditor?'ready':'none'))})">Try: Introspect Active Tab</button>


active-file:codeEditor:isLoading -- Loading Flag

Returns true while the active editor is still fetching / parsing its initial content (and briefly during subsequent reloads).

Arg Type Description
activeTabId string (optional) When provided, errors out if the active tab's id does not match (prevents racing with a tab switch)
callback function (err, isLoading: boolean)

socket.fire("webapp::instance::request", "active-file:codeEditor:isLoading",
    function (err, loading) {
        if (err) return console.error(err);
        console.log(loading ? "still loading" : "ready");
    }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','active-file:codeEditor:isLoading',function(e,l){if(e)return alert(e.message);alert('isLoading: '+l)})">Try: Check Loading State</button>


File-system Bridge

The fs:* events expose the same virtual filesystem that the file-manager webapp uses, bound to the editor's own fs decorator so writes also trigger the universal fs-event bridge (afterWrite, afterRemove, afterCwd -- see File Manager docs for subscription). Within an unauthenticated embedding context, operations are sandboxed to the input:// scheme (browser-memory, isolated per tab, destroyed on refresh).
A common pattern: write a markdown file via fs:write, open it as a markdown tab via files:open -- the tab subscribes to afterWrite and auto-refreshes on every subsequent write, giving a live preview without re-opening.


fs:write -- Write a File

Writes content to path. Creates the file (and intermediate directories under input://) if missing.

Arg Type Description
path string Target path (e.g. input://notes.md)
content string \ Blob \ ArrayBuffer File body
callback function (err)

socket.fire("webapp::instance::request", "fs:write",
    "input://hello.txt", "Hello, world!",
    function (err) { console.log(err || "written"); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:write','input://hello.txt','Hello from code-editor docs @ '+new Date().toISOString(),function(e){if(e)alert('Error: '+e.message);else alert('Wrote input://hello.txt')})">Try: Write hello.txt</button>


fs:read -- Read a File

Reads path as UTF-8 text.

Arg Type Description
path string Source path
callback function (err, content: string)

socket.fire("webapp::instance::request", "fs:read", "input://hello.txt",
    function (err, content) {
        if (err) return console.error(err);
        console.log("content:", content);
    }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:read','input://hello.txt',function(e,c){if(e)alert('Error: '+e.message);else alert('Content:\n'+c)})">Try: Read hello.txt</button>


fs:exists -- Check Existence

Arg Type Description
path string Path to check
callback function (err, exists: boolean)

socket.fire("webapp::instance::request", "fs:exists", "input://hello.txt",
    function (err, exists) { console.log(exists ? "yes" : "no"); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:exists','input://hello.txt',function(e,x){if(e)alert('Error: '+e.message);else alert('exists: '+x)})">Try: Check hello.txt</button>


fs:stats -- File Metadata

Arg Type Description
path string Target path
callback function (err, info) with &#x7B;length, mtime, type, ...&#x7D; fields depending on backend

socket.fire("webapp::instance::request", "fs:stats", "input://hello.txt",
    function (err, info) { console.log(info); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:stats','input://hello.txt',function(e,i){if(e)alert('Error: '+e.message);else alert('Stats:\n'+JSON.stringify(i,null,2))})">Try: Stat hello.txt</button>


fs:mkdir -- Create a Directory (non-recursive)

Fails when the parent directory does not exist. Use fs:mkdirp to create intermediate levels.

Arg Type Description
path string Directory path (trailing / optional)
callback function (err)

socket.fire("webapp::instance::request", "fs:mkdir", "input://data/",
    function (err) { console.log(err || "created"); }
);

fs:mkdirp -- Create a Directory (recursive)

Like mkdir -p: creates every missing level in the path.

Arg Type Description
path string Directory path
callback function (err)

socket.fire("webapp::instance::request", "fs:mkdirp",
    "input://proj/src/components/",
    function (err) { console.log(err || "created"); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:mkdirp','input://proj/src/components/',function(e){if(e)alert('Error: '+e.message);else alert('Created input://proj/src/components/')})">Try: Create proj/src/components/</button>


fs:remove -- Delete a File or Directory

Arg Type Description
path string File or directory to remove
callback function (err)

socket.fire("webapp::instance::request", "fs:remove", "input://hello.txt",
    function (err) { console.log(err || "removed"); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:remove','input://hello.txt',function(e){if(e)alert('Error: '+e.message);else alert('Removed input://hello.txt')})">Try: Remove hello.txt</button>


fs:mv -- Move or Rename

Arg Type Description
src string Source path
dst string Destination path
callback function (err)

socket.fire("webapp::instance::request", "fs:mv",
    "input://notes.md", "input://archive/notes.md",
    function (err) { console.log(err || "moved"); }
);

fs:ls -- List Directory

Returns an array of entry descriptors for the given directory.

Arg Type Description
path string Directory to list
callback function (err, entries: Array) -- each entry has &#x7B;name, type, ...&#x7D; fields

socket.fire("webapp::instance::request", "fs:ls", "input://",
    function (err, list) { console.log(list); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:ls','input://',function(e,l){if(e)alert('Error: '+e.message);else alert('Entries at input://\n'+(l&&l.length?l.map(function(x){return (x.type||'?')+' '+(x.name||x.path||JSON.stringify(x))}).join('\n'):'(empty)'))})">Try: List input://</button>


fs:cwd -- Get or Set Current Working Directory

When called with a string, changes the sidebar's current working directory (and emits afterCwd). When called with only a callback, returns the current path.

Arg Type Description
path string (optional) New cwd
callback function (err, cwd: string)

// Get
socket.fire("webapp::instance::request", "fs:cwd",
    function (err, cwd) { console.log("cwd:", cwd); }
);

// Set
socket.fire("webapp::instance::request", "fs:cwd", "input://proj/",
    function (err, cwd) { console.log("now at:", cwd); }
);

<button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:cwd',function(e,c){if(e)alert('Error: '+e.message);else alert('cwd: '+c)})">Try: Get cwd</button><button onclick="window._ws('ceSocket')&&window.ceSocket.fire('webapp::instance::request','fs:mkdirp','input://proj/',function(){window.ceSocket.fire('webapp::instance::request','fs:cwd','input://proj/',function(e,c){if(e)alert('Error: '+e.message);else alert('cwd: '+c)})})">Try: Set cwd -> input://proj/</button>


Complete Example

<!DOCTYPE html>
<html>
<head><title>Embedded Code Editor</title></head>
<body>
    <div style="display:flex;gap:8px;padding:10px;flex-wrap:wrap;">
        <button id="set-code">Load Sample</button>
        <button id="get-code">Read Code</button>
        <button id="set-python">Python Mode</button>
        <button id="readonly">Read-Only</button>
        <button id="add-markers">Show Errors</button>
    </div>

    <iframe id="editor" src="https://sgapps.io/online/webapp/code-editor"
        width="100%" height="500" frameborder="0" allow="clipboard-write"></iframe>

    <pre id="output" style="background:#f6f8fa;padding:10px;max-height:200px;overflow:auto;"></pre>

    <script src="https://sgapps.io/components/window-socket/index.js"></script>
    <script>
        var socket = new WindowSocket(document.getElementById('editor').contentWindow);
        socket.start();

        socket.on("webapp::connection::ping", function () {
            socket.fire("webapp::instance::embed-mode", true);
        });

        document.getElementById('set-code').onclick = function () {
            socket.fire("webapp::instance::request", "active-file:codeEditor:value",
                "def fibonacci(n):\n    a, b = 0, 1\n    for _ in range(n):\n        a, b = b, a + b\n    return a\n\nprint(fibonacci(10))");
            socket.fire("webapp::instance::request", "active-file:codeEditor:syntax", "python");
        };

        document.getElementById('get-code').onclick = function () {
            socket.fire("webapp::instance::request", "active-file:codeEditor:value",
                function (err, v) {
                    if (err) return console.error(err);
                    document.getElementById('output').textContent = v;
                });
        };

        document.getElementById('set-python').onclick = function () {
            socket.fire("webapp::instance::request", "active-file:codeEditor:syntax", "python");
        };

        document.getElementById('readonly').onclick = function () {
            socket.fire("webapp::instance::request", "active-file:codeEditor:options", { readOnly: true });
        };

        document.getElementById('add-markers').onclick = function () {
            socket.fire("webapp::instance::request", "active-file:markers", [
                { startLine: 2, startCol: 1, endLine: 2, endCol: 20, message: "Consider using a list comprehension", severity: 4 }
            ]);
        };
    </script>
</body>
</html>
sgapps.io