Skip to main content

Getting started

Install

npm install @react-x11/components

react and react-x11 are peer dependencies, deliberately. Registering a host element mutates module-level state inside react-x11 — the registry map, and the set of kinds paint order filters on — so a second copy of the renderer in one app leaves you with an element that lays out correctly, reports a sensible rect, and never paints, with no error anywhere.

npm install react react-x11

Core needs to be 2.0.0 or newer — that is the release the subpaths this package imports (react-x11/host, /node, /style) arrived in.

TypeScript users also want @types/react, since React ships no types of its own. If you set skipLibCheck: false, core's own declarations need "lib": ["esnext"] — they reference Symbol.asyncDispose. The default skipLibCheck: true sidesteps it.

Use a component

import { Code } from '@react-x11/components';

function App() {
return (
<window width={480} height={240} title="components">
<box style={{ flexGrow: 1, padding: 16 }}>
<Code source={source} lang="ts" lineNumbers />
</box>
</window>
);
}

Importing a component is what teaches react-x11 its element, so there is no setup call to remember and no registration to run at startup. That is also what makes the tree-shaking work: registration happens in the module a bundler keeps only when the component is used.

Deep imports

Every component has a subpath of its own, for apps without a bundler and for anyone who would rather be explicit:

import { Code } from '@react-x11/components/code';
import { Terminal } from '@react-x11/components/terminal';

The barrel and the subpath are the same module either way.

Optional dependencies

Nothing below is required to install the package, and nothing below throws when it is missing — each has a status and a fallback instead.

You wantInstallWithout it
<Terminal backend="vt">npm i node-pty or @lydell/node-ptystatus is 'unavailable', fallback renders
<Terminal> on an embedded emulatorxterm, urxvt or alacritty on PATHbackend="auto" falls through to vt
<MediaPlayer>mpv or VLC on PATHfallback renders, onError names what it looked for
Recurring events in the desktop calendarnpm i ical.jsstatus is 'unavailable'; the calendar renders without dots

@xterm/headless is an optional dependency, not a peer: it is 2 MB and installs by default, because nothing else would bring it. The pty is an optional peer because node-pty unpacks to 64 MB and builds a native addon, which is not something a package a calendar app installed may drag in.

TypeScript

The package is written in TypeScript and ships its own declarations, so there is no @types package to install. Point your compiler at react-x11's JSX namespace and the host elements type-check:

{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react-x11"
}
}

Importing a component teaches JSX its element too, so <codeeditor> is a typed tag as soon as CodeEditor is in scope. Props types are exported under their component's name:

import type { CodeEditorProps } from '@react-x11/components';

Testing

react-x11's test harness runs node-x11's pure-JavaScript X server in-process, so a test that renders one of these components needs no $DISPLAY and no xvfb. That is how this repo's own suite covers a terminal, a media player and a system tray on a CI machine with none of them installed — the ProcessHost seam stands in for the spawn, and assertions are made about what would have run.

Where to next

The reference is one page per component. Each starts with the shortest snippet that works and ends with the decisions that look like gaps and are not.