Getting Started - rahulpandita/react-term GitHub Wiki

This guide covers installing react-term, configuring cross-origin isolation for SharedArrayBuffer, and connecting the terminal to a PTY or WebSocket.

Prerequisites

  • Node.js ≥ 18 (for development in the monorepo; no Node.js runtime requirement in the browser)
  • pnpm ≥ 8 for the monorepo: npm install -g pnpm
  • Cross-origin isolation — required to enable SharedArrayBuffer and full off-main-thread mode. The page must be served with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp
  • WebGL2 — required for hardware-accelerated rendering; falls back to Canvas 2D automatically when unavailable

Installation

For a React (web) project:

npm install `@next_term/react` `@next_term/web`
# or
pnpm add `@next_term/react` `@next_term/web`
# or
yarn add `@next_term/react` `@next_term/web`

For a React Native project:

npm install `@next_term/native` `@next_term/core`
# Peer dependencies:
npm install `@shopify/react-native-skia` react-native-gesture-handler

Configuration

SharedArrayBuffer requires cross-origin isolation. Without these headers, react-term automatically falls back to main-thread parsing and Canvas 2D rendering.

Express

app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
  next();
});

Vite

// vite.config.ts
export default {
  server: {
    headers: {
      'Cross-Origin-Opener-Policy': 'same-origin',
      'Cross-Origin-Embedder-Policy': 'require-corp',
    },
  },
};

Next.js

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
        { key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' },
      ],
    }];
  },
};

Note: require-corp blocks cross-origin resources that lack a Cross-Origin-Resource-Policy header. CDN-hosted fonts and images may need crossorigin="anonymous" and a CORP header on the server.

Rendering Strategies

react-term selects the best strategy automatically at runtime:

Strategy Condition Benefit
Full Worker SAB + OffscreenCanvas available Zero main-thread parser and render work
Parser Worker SAB available, no OffscreenCanvas Parser off-thread; rendering on main thread
Main Thread Neither available Universal fallback via Canvas 2D

The renderMode prop on Terminal can override the automatic selection to force 'webgl' or 'canvas2d'.

Connecting to a PTY or WebSocket

The onData callback fires whenever the user types or pastes. Forward the data to your PTY process or WebSocket, then write responses back with ref.current?.write().

import { useRef, useEffect } from 'react';
import { Terminal, type TerminalHandle } from '`@next_term/react`';

function PtyTerminal() {
  const ref = useRef(TerminalHandle)(null);
  const socket = useRef(WebSocket)();

  useEffect(() => {
    socket.current = new WebSocket('wss://yourserver/pty');
    socket.current.binaryType = 'arraybuffer';

    socket.current.onmessage = (e) => {
      ref.current?.write(
        e.data instanceof ArrayBuffer ? new Uint8Array(e.data) : e.data,
      );
    };

    return () => socket.current?.close();
  }, []);

  return (
    (Terminal
      cols={80}
      rows={24}
      autoFit={true}
      onData={(data) =) socket.current?.send(data)}
      onResize={(cols, rows) => {
        socket.current?.send(JSON.stringify({ type: 'resize', cols, rows }));
      }}
      ref={ref}
    />
  );
}