The editor and live output
How JSLab runs your code as you type, logs values with Auto Log, magic comments and logpoints, and stops runaway code.
The editor is Monaco, the engine behind VS Code. It has TypeScript, JavaScript, TSX and JSX modes, bracket matching, folding and multi-cursor editing. Pick a tab’s language from the status bar or Actions → Language.
TypeScript diagnostics show inline as you type, but they never block a run. For Vim key bindings, turn on Vim Keys in Settings → Editor; ⌘R still runs in every Vim mode.
TypeScript and JSX
Write TypeScript, JavaScript, TSX or JSX, and await at the top level without wrapping anything.
type User = { name: string; age: number };
const users: User[] = [
{ name: "Ada", age: 36 },
{ name: "Alan", age: 41 },
];
const oldest = (list: User[]) => list.reduce((a, b) => (a.age > b.age ? a : b));
oldest(users);
await new Promise((resolve) => setTimeout(resolve, 300));
"waited 300 ms";
Each tab has a language — TypeScript, JavaScript, TSX or JSX — set from the status bar or Settings → General → Default Language. Types are checked in the editor and stripped when the code runs, so a type error is an underline, never a failed run. Top-level await works without wrapping anything.
The editor knows the tab’s runtime: a Bun tab sees Bun’s and Node’s types, a Browser & Node APIs tab sees Node’s and the DOM’s, and a Browser tab sees the DOM’s. Types for the packages you import load as you type.
Editing shortcuts
Multiple cursors, moving and duplicating lines, and the rest of the editor's commands all have shortcuts.
// Try it: select "price" on line 3 and press ⌘D three times, then type "cost".
const items = [4, 10, 25];
const price = items.map((price) => price * 1.2);
price;
The editor’s own commands are JSLab commands, so they have shortcuts you can change and they appear in the command palette: find and replace, go to line, select the next match (⌘D), add a cursor above or below, split a selection into lines, move a line (⌃⌘↑ and ⌃⌘↓), duplicate it (⇧⌘D), join, sort and delete lines, expand a selection, and line and block comments. Clear Editor empties the tab in one undoable step. See Keyboard shortcuts.
Auto Run
Your code runs a moment after you stop typing; Run, Stop and Kill are there when you want them.
// Change 41 to any number and pause: the result updates on its own.
const answer = 41 + 1;
answer;
// Runs that keep going, like this timer, can be stopped with ⇧⌘R.
let ticks = 0;
const timer = setInterval(() => {
ticks++;
console.log(`tick ${ticks}`);
if (ticks === 3) clearInterval(timer);
}, 400);
Auto Run runs your code a short delay after you stop typing. The delay is Auto Run Delay in Settings → Advanced: 300 ms by default, anywhere from 0 to 5,000 ms.
- ⌘R always runs immediately, whether or not Auto Run is on.
- ⌥⌘A (Toggle Auto Run) turns it on or off. So does Auto Run in Settings → General.
- It also runs the tab when you switch its runtime, toggle a logpoint, or install a package the last run was missing.
Auto Log
Every top-level expression is logged beside its line, so you rarely need console.log.
// Expressions on their own line show a value.
const xs = [3, 1, 2];
xs.sort();
xs.length;
let count = 0;
count++;
Math.max(...xs);
xs.map((x) => x * 10);
Auto Log shows the value of each top-level expression, with no console.log needed.
const user = { name: "Ada", langs: ["js", "ts"] };
user.langs.length; // Auto Log shows 2 on this line
- Assignments,
x++andconsole.*calls are never auto-logged. - A leading string literal at the top of a file is logged too.
"use strict"isn’t, because it’s a directive. - ⌥⌘L (Toggle Auto Log) turns it off, so you see only what you log yourself.
- Show Undefined in Settings → Advanced decides whether an expression whose value is
undefinedgets its own row. It’s off by default.
Magic comments
End a line with //? and JSLab logs exactly that statement, even inside a function or a loop.
const prices = [9.99, 19.5, 4.25];
function withTax(price: number) {
return price * 1.2; //?
}
for (const p of prices) /*?*/ {
withTax(p);
}
const { length } = prices; //?
const names = [{ n: "Ada" }, { n: "Alan" }]; //? $.length
A magic comment logs exactly what you ask for, whether or not Auto Log is on.
const words = "the quick brown fox".split(" ");
// Logs the array.
words //?
// Logs the mapped array, before .join runs.
words.map((w) => w.toUpperCase()) /*?*/ .join("-")
// Logs 4.
words //? $.length
// Logs each word as the loop runs.
for (const word of words) /*?*/ {}
value //?logsvalue./*?*/works inline: mid-expression, or before a block’s opening brace, where it logs each pass.//? $.lengthlogs an expression built from the value, which is$.- On
const { a, b } = …,//?logs an object of the names you bound; onreturnorthrow, the value. - A
//?with nothing to log is a yellow warning underline, never an error. A line with both a//?and a logpoint logs once.
⌥⇧⌘/ (Toggle Magic Comment) adds or removes one on the current line.
Logpoints
Click beside a line number, or press F9, to log that line without editing your code.
// Put a logpoint on line 5 or 6: click left of its line number, or press F9 there.
const prices = [9.99, 19.5, 4.25];
const total = prices.reduce((sum, p) => sum + p, 0);
const rounded = Math.round(total * 100) / 100;
const label = `Total: ${rounded}`;
label;
A logpoint logs a line without changing its text. Click the gutter beside a line, or press F9 with the caret on it, to toggle one. ⇧⌘F9 clears every logpoint in the tab.
- A logpoint follows its line as you edit above or below it.
- Logpoints belong to one tab and aren’t saved. They reset when you close the tab or restart JSLab.
- Toggling a logpoint schedules a run, even if nothing else changed.
Loop protection
An endless loop stops itself with an error naming the line, and a stuck run can always be killed.
// i never reaches 10: after 2,000 passes the loop is stopped, and the error names its line.
let i = 0;
while (i < 10) {
i = i * 2;
}
for, while, do…while, for…in and for…of loops are stopped after too many iterations, so a slip like while (true) can’t hang a run.
The limit is Loop Limit in Settings → Advanced: 2,000 iterations by default, adjustable from 100 to 10,000,000. Turn the feature off with Loop Protection in the same place, or with Toggle Loop Protection in the command palette.
Show Transpiled Output
Show Transpiled Output displays the JavaScript your tab actually runs, next to your code.
Actions → Show Transpiled Output puts the Babel output for the current tab in the side bar. Hide instrumentation switches between the code as it runs and the code without Auto Log, logpoint and loop-protection instrumentation. The panel refreshes on each run, and marks itself Stale — run to refresh once you’ve edited past the run it shows.
Which syntax proposals the transform accepts, such as decorators or the pipeline operator, is set in Settings → Build. See Settings.
__jl is reserved for JSLab’s own logging: declaring it fails the run with a message saying so. After 500 transform warnings, the rest are summed up in one line.
Stop, Kill and unresponsive tabs
A run stays active while timers or servers are open, and Stop closes them all.
// This run stays active for three ticks, then ends by itself. ⇧⌘R stops it early.
let ticks = 0;
const timer = setInterval(() => {
ticks++;
console.log(`tick ${ticks}`);
if (ticks === 3) clearInterval(timer);
}, 500);
"started";
A run stays active while it has open timers, servers, sockets or child processes; the status bar says so, and Stop closes them all. Each run is its own process (or a freshly reloaded page in a browser tab), so a crash never takes JSLab down. process.exit() flushes its output before it ends the run.
- ⇧⌘R (Stop) stops a run gracefully. If the run doesn’t respond, JSLab kills it after 500 ms.
- ⌥⌘R (Kill) kills it immediately.
If your code stops responding altogether, JSLab shows a This tab isn’t responding prompt with Kill and Wait. It appears after 3 seconds without a response by default; change that with Unresponsive Timeout in Settings → Advanced, from 1,000 to 60,000 ms.
Zoom
⌘=, ⌘- and ⌘0 (Zoom In, Zoom Out and Actual Size) scale the editor, the output panel and the side bar together. The same value is Zoom in Settings → Appearance.
Related
- The output panel: everything this page logs ends up there.
- Keyboard shortcuts: every default shortcut.