Claude
Skills
Sign in
Back

xtermjs-skill

Included with Lifetime
$97 forever

Expert guidance for building, configuring, and integrating xterm.js terminal emulators in web and Electron applications. Use this skill whenever the user mentions xterm, xterm.js, @xterm/xterm, terminal emulator in the browser, web terminal, WebSSH, in-browser shell, or asks about addons like FitAddon, WebglAddon, SearchAddon, AttachAddon, or integration with node-pty. Also trigger for questions about ANSI/VT sequences, terminal theming, PTY over WebSocket, custom key handlers, parser hooks, or embedding a terminal in React/Vue/Angular/Electron apps. TRIGGER WHEN: the user mentions xterm, xterm.js, @xterm/xterm, terminal emulator in the browser, web terminal, WebSSH, in-browser shell, or asks about addons like FitAddon, WebglAddon, SearchAddon, AttachAddon, or integration with node-pty. DO NOT TRIGGER WHEN: the user wants a native OS terminal (not browser-based) or a non-xterm terminal library (e.g. VT100 emulator in Python).

Web Dev

What this skill does


# xterm.js Development Skill

xterm.js (`@xterm/xterm`) is a full-featured terminal emulator that runs in the browser or
Electron. It is NOT a shell -- it must be connected to a backend process (e.g. via node-pty +
WebSocket) to execute commands.

---

## 1. Installation

```bash
npm install @xterm/xterm
# Required addons (install only what you need):
npm install @xterm/addon-fit @xterm/addon-attach @xterm/addon-web-links \
            @xterm/addon-search @xterm/addon-webgl @xterm/addon-clipboard \
            @xterm/addon-web-fonts @xterm/addon-unicode11
```

Always import the CSS:
```html
<link rel="stylesheet" href="node_modules/@xterm/xterm/css/xterm.css" />
```
Or in JS/TS:
```ts
import '@xterm/xterm/css/xterm.css';
```

---

## 2. Basic Setup

```ts
import { Terminal } from '@xterm/xterm';

const term = new Terminal({
  cols: 80,
  rows: 24,
  cursorBlink: true,
  scrollback: 5000,
  fontFamily: '"Cascadia Code", Menlo, monospace',
  fontSize: 14,
  theme: {
    background: '#1e1e1e',
    foreground: '#d4d4d4',
    cursor: '#d4d4d4',
  },
});

term.open(document.getElementById('terminal')!);
term.write('Hello from \x1B[1;32mxterm.js\x1B[0m\r\n$ ');
```

**Critical**: Always call `term.open(element)` AFTER the element is in the DOM.
Use `\r\n` (not just `\n`) for newlines when writing directly.

---

## 3. Official Addons

| Addon | Package | Purpose |
|---|---|---|
| FitAddon | `@xterm/addon-fit` | Resize terminal to fill its container |
| AttachAddon | `@xterm/addon-attach` | Connect to a WebSocket backend |
| SearchAddon | `@xterm/addon-search` | In-terminal text search |
| WebglAddon | `@xterm/addon-webgl` | GPU-accelerated WebGL2 renderer |
| WebLinksAddon | `@xterm/addon-web-links` | Clickable URLs |
| ClipboardAddon | `@xterm/addon-clipboard` | Browser clipboard integration |
| WebFontsAddon | `@xterm/addon-web-fonts` | Wait for web fonts before rendering |
| Unicode11Addon | `@xterm/addon-unicode11` | Unicode 11 character width support |
| LigaturesAddon | `@xterm/addon-ligatures` | Font ligature support (DEPRECATED with Canvas renderer removal; prefer WebGL + font features) |

### Loading addons

```ts
import { FitAddon } from '@xterm/addon-fit';
import { WebglAddon } from '@xterm/addon-webgl';
import { WebLinksAddon } from '@xterm/addon-web-links';
import { SearchAddon } from '@xterm/addon-search';

const fitAddon = new FitAddon();
const searchAddon = new SearchAddon();

term.loadAddon(fitAddon);
term.loadAddon(searchAddon);
term.loadAddon(new WebLinksAddon());

term.open(document.getElementById('terminal')!);

// WebGL: load AFTER open(), handle fallback
try {
  const webgl = new WebglAddon();
  webgl.onContextLoss(() => webgl.dispose()); // fallback on context loss
  term.loadAddon(webgl);
} catch {
  console.warn('WebGL2 not available, falling back to canvas renderer');
}

fitAddon.fit();
```

---

## 4. FitAddon: Responsive Resizing

FitAddon resizes cols/rows to fit the container's pixel dimensions.

```ts
// Resize on window resize
const ro = new ResizeObserver(() => fitAddon.fit());
ro.observe(document.getElementById('terminal')!);

// Or with window resize event (less precise):
window.addEventListener('resize', () => fitAddon.fit());
```

**Gotcha**: Container must have explicit dimensions (CSS `width`/`height`).
FitAddon returns `undefined` if the container has zero size.

---

## 5. Backend Integration: node-pty + WebSocket

### Frontend (AttachAddon)

```ts
import { AttachAddon } from '@xterm/addon-attach';

const socket = new WebSocket('ws://localhost:3000/ws');
const attachAddon = new AttachAddon(socket);
term.loadAddon(attachAddon);

// Sync terminal resize with PTY on the server
term.onResize(({ cols, rows }) => {
  socket.send(JSON.stringify({ type: 'resize', cols, rows }));
});
```

### Backend (Node.js + node-pty)

```ts
import * as pty from 'node-pty';
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 3000 });

wss.on('connection', (ws) => {
  const shell = process.platform === 'win32' ? 'powershell.exe' : 'bash';
  const ptyProcess = pty.spawn(shell, [], {
    name: 'xterm-color',
    cols: 80,
    rows: 24,
    env: process.env,
  });

  ptyProcess.onData((data) => ws.send(data));
  ws.on('message', (msg) => {
    const parsed = JSON.parse(msg.toString());
    if (parsed.type === 'resize') {
      ptyProcess.resize(parsed.cols, parsed.rows);
    } else {
      ptyProcess.write(msg.toString());
    }
  });
  ws.on('close', () => ptyProcess.kill());
});
```

For simple bidirectional use (no resize), AttachAddon handles piping automatically;
manual `term.onData` / `pty.onData` wiring is only needed for custom protocols.

---

## 6. Manual Data Wiring (without AttachAddon)

```ts
// PTY → terminal
ptyProcess.onData((data) => term.write(data));

// Terminal → PTY (user keystrokes)
term.onData((data) => ptyProcess.write(data));

// Binary events (e.g., certain mouse reports)
term.onBinary((data) => ptyProcess.write(data));
```

---

## 7. Theming

Pass an `ITheme` object in options or use `term.options.theme = {...}` at runtime:

```ts
const darkTheme = {
  background: '#0d1117',
  foreground: '#c9d1d9',
  cursor: '#58a6ff',
  cursorAccent: '#0d1117',
  selectionBackground: '#264f78',
  black:   '#484f58', red:     '#ff7b72', green:   '#3fb950', yellow:  '#d29922',
  blue:    '#58a6ff', magenta: '#bc8cff', cyan:    '#39c5cf', white:   '#b1bac4',
  brightBlack:   '#6e7681', brightRed:   '#ffa198', brightGreen:  '#56d364',
  brightYellow:  '#e3b341', brightBlue:  '#79c0ff', brightMagenta:'#d2a8ff',
  brightCyan:    '#56d4dd', brightWhite: '#f0f6fc',
};

// Apply at construction
const term = new Terminal({ theme: darkTheme });

// Or update at runtime
term.options.theme = darkTheme;
```

---

## 8. Key Event Handling

```ts
// Intercept keys before terminal processes them
// Return false to suppress, true to allow
term.attachCustomKeyEventHandler((ev: KeyboardEvent) => {
  // Example: Ctrl+Shift+C → copy
  if (ev.ctrlKey && ev.shiftKey && ev.key === 'C') {
    // Modern clipboard API (navigator.clipboard requires HTTPS/localhost)
    const selection = term.getSelection();
    if (selection) navigator.clipboard.writeText(selection);
    return false; // don't pass to terminal
  }
  return true;
});
```

---

## 9. Search (SearchAddon)

```ts
// Find next/previous
searchAddon.findNext('search term', {
  regex: false,
  wholeWord: false,
  caseSensitive: false,
  incremental: false,       // true = highlight while typing
  decorations: {
    matchBackground: '#ffff0040',
    matchBorder: '#ffff00',
    matchOverviewRuler: '#ffff00',
    activeMatchBackground: '#ff000080',
    activeMatchBorder: '#ff0000',
    activeMatchColorOverviewRuler: '#ff0000',
  },
});
searchAddon.findPrevious('search term');
```

---

## 10. Decorations and Markers

```ts
// Add a marker on the current row
const marker = term.registerMarker(0); // 0 = current row offset

// Add a decoration (e.g. highlight a line)
const decoration = term.registerDecoration({
  marker,
  overviewRulerOptions: { color: '#ff0000' },
});

decoration?.onRender((element) => {
  element.style.backgroundColor = 'rgba(255,0,0,0.2)';
});
```

---

## 11. Parser Hooks (Custom Sequences)

```ts
// Register a custom OSC sequence handler (e.g. OSC 1337)
term.parser.registerOscHandler(1337, (data: string) => {
  console.log('Custom OSC 1337 payload:', data);
  return true; // handled
});

// Register a custom CSI sequence handler
term.parser.registerCsiHandler({ final: 'z' }, (params) => {
  console.log('Custom CSI z params:', params);
  return true;
});
```

---

## 12. React Integration Pattern

```tsx
import { useEffect, useRef } from 'react';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import '@xterm/xterm/css/xterm.css';

export function XTerminal() {
  const containerRef = useRef<HTMLDivElement>(null);
  const termRef = useRef<Terminal | null>(null);

  useEffect(() => {
    const term = new Terminal({ cu

Related in Web Dev