react-x11 2.51.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +87 -54
  2. package/docs/README.md +410 -0
  3. package/docs/accessibility.md +628 -0
  4. package/docs/appearance.md +416 -0
  5. package/docs/architecture/accessibility.md +470 -0
  6. package/docs/architecture/animation.md +707 -0
  7. package/docs/architecture/container-queries.md +525 -0
  8. package/docs/architecture/custom-layout.md +334 -0
  9. package/docs/architecture/drag-and-drop.md +941 -0
  10. package/docs/architecture/element-layer-contents.md +622 -0
  11. package/docs/architecture/frame-pacing.md +255 -0
  12. package/docs/architecture/grid-layout.md +358 -0
  13. package/docs/architecture/protocol-efficiency.md +357 -0
  14. package/docs/architecture/video.md +1149 -0
  15. package/docs/architecture/windowed-regions.md +854 -0
  16. package/docs/click-to-component.md +125 -0
  17. package/docs/clipboard.md +281 -0
  18. package/docs/components.md +1749 -0
  19. package/docs/dbus.md +277 -0
  20. package/docs/debugging.md +464 -0
  21. package/docs/desktop-calendar.md +284 -0
  22. package/docs/desktop.md +648 -0
  23. package/docs/devtools.md +250 -0
  24. package/docs/drag-and-drop.md +663 -0
  25. package/docs/ecosystem/animation.md +394 -0
  26. package/docs/ecosystem/data-fetching.md +201 -0
  27. package/docs/ecosystem/dev-tooling.md +436 -0
  28. package/docs/ecosystem/forms.md +313 -0
  29. package/docs/ecosystem/headless.md +219 -0
  30. package/docs/ecosystem/i18n.md +89 -0
  31. package/docs/ecosystem/icons.md +410 -0
  32. package/docs/ecosystem/layout.md +216 -0
  33. package/docs/ecosystem/routing.md +146 -0
  34. package/docs/ecosystem/state.md +361 -0
  35. package/docs/ecosystem/testing.md +500 -0
  36. package/docs/ecosystem/theming.md +540 -0
  37. package/docs/ecosystem.md +473 -0
  38. package/docs/elements.md +2762 -0
  39. package/docs/embedding.md +288 -0
  40. package/docs/events.md +1025 -0
  41. package/docs/extending.md +2242 -0
  42. package/docs/eyedropper.md +223 -0
  43. package/docs/filedialog.md +258 -0
  44. package/docs/frame.md +580 -0
  45. package/docs/gl.md +170 -0
  46. package/docs/globalmenu.md +278 -0
  47. package/docs/glx.md +137 -0
  48. package/docs/macos.md +3295 -0
  49. package/docs/notifications.md +164 -0
  50. package/docs/packaging.md +611 -0
  51. package/docs/permissions.md +148 -0
  52. package/docs/react-features.md +430 -0
  53. package/docs/remote.md +223 -0
  54. package/docs/scale.md +339 -0
  55. package/docs/security.md +132 -0
  56. package/docs/styling.md +1928 -0
  57. package/docs/system.md +599 -0
  58. package/docs/testing.md +514 -0
  59. package/docs/typescript.md +117 -0
  60. package/docs/uri-schemes.md +380 -0
  61. package/docs/wayland-backend.md +591 -0
  62. package/docs/wayland.md +545 -0
  63. package/docs/windows-embedding.md +271 -0
  64. package/docs/windows-gl.md +221 -0
  65. package/docs/windows-integrations.md +233 -0
  66. package/docs/windows.md +1404 -0
  67. package/package.json +10 -3
  68. package/src/bus.js +39 -26
  69. package/src/cli/create.d.ts +43 -0
  70. package/src/cli/create.js +305 -0
  71. package/src/cli/env.js +484 -0
  72. package/src/cli/index.js +29 -2
  73. package/src/cli/templates/AGENTS.template.md +195 -0
  74. package/src/cli/templates/DESIGN.template.md +269 -0
  75. package/src/desktopintegration.js +2 -1
  76. package/src/desktopsettings.js +193 -24
  77. package/src/filedialog.js +3 -3
  78. package/src/keyboardstate.js +28 -0
  79. package/src/node.d.ts +10 -10
  80. package/src/portal.js +31 -0
  81. package/src/screencolor.js +5 -10
  82. package/src/types/system.d.ts +8 -6
  83. package/src/wayland/app.js +59 -0
  84. package/src/wayland/clipboard.js +14 -7
  85. package/src/wayland/connection.js +3 -0
  86. package/src/wayland/context2d.js +129 -10
  87. package/src/wayland/protocols/index.json +6 -0
  88. package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
  89. package/src/wayland/seat.js +28 -1
  90. package/src/wayland/swapchain.js +23 -0
  91. package/src/wayland/xkb.js +137 -0
package/docs/README.md ADDED
@@ -0,0 +1,410 @@
1
+ # react-x11 documentation
2
+
3
+ react-x11 has **two backends**: X11 (a Linux desktop, a forwarded display,
4
+ XQuartz) and Cocoa (a native Mac app, no X server anywhere). The same tree,
5
+ components, styles and hooks run on both, and `createRoot()` picks — Cocoa
6
+ on macOS where the bridge is installed, X11 otherwise. Every page below is
7
+ about both unless it says otherwise; where a backend changes the answer, it
8
+ is called out where the answer is. A native Wayland backend exists and is
9
+ opt-in ([wayland-backend.md](wayland-backend.md), with its research RFC in
10
+ [wayland.md](wayland.md)); Windows ships too
11
+ ([windows-integrations.md](windows-integrations.md) for what it reaches,
12
+ [windows.md](windows.md) for why it is built the way it is).
13
+
14
+ - [macos.md](macos.md) — the Cocoa backend: what a retained layer tree
15
+ changes about a renderer built for a drawing protocol, the two presenters
16
+ (a bitmap surface per window, and a CALayer per node) and which one is the
17
+ measured default, text through CoreText, input off an `NSApplication`
18
+ pump driven by Node's loop, native controls, the menu bar, layer
19
+ promotion, running as an app bundle, and what does not map — no window
20
+ manager, no cross-process embedding. Also the design record for the parts
21
+ still ahead.
22
+ - [elements.md](elements.md) — the host elements: `<window>`, `<popup>`,
23
+ `<box>`, `<text>`, `<textinput>`, `<textarea>`, `<image>`, `<canvas>`,
24
+ `<svg>`, `<foreign>`, their props and refs — including
25
+ [selecting read-only text](elements.md#selecting-text) with `selectable`.
26
+ - [styling.md](styling.md) — the `style` prop: layout and paint properties,
27
+ `:hover`/`:focus`/`:active`/`:disabled` blocks, transitions, theme tokens,
28
+ window size and container queries, `createStyles`, and
29
+ [a font file of your own](styling.md#a-font-file-of-your-own) —
30
+ `openFont`/`loadFont`/`useFont`.
31
+ - [components.md](components.md) — widget components built on the
32
+ primitives: theming, the basic controls (`Button`, `Checkbox`,
33
+ `Radio`/`RadioGroup`, `Switch`, `ProgressBar`), `Select`, `Slider`,
34
+ `Tooltip`, `Dialog`, `MenuBar`/`ContextMenu`, `Tabs`, `Table`,
35
+ `SplitPane`, and the `useAnchor` popup placement hook.
36
+ - [globalmenu.md](globalmenu.md) — handing a window's menu bar to wherever
37
+ the platform keeps menus, with no configuration: the macOS menu bar on the
38
+ cocoa backend, the desktop's panel over `com.canonical.dbusmenu` where one
39
+ is running, and the drawn bar everywhere else. The item vocabulary
40
+ `MenuBar` shares with all three, why detection means "a panel is running"
41
+ rather than "one could be started", the diff that decides between patching
42
+ properties and invalidating a layout, why `Control` in a shortcut means ⌘
43
+ on a Mac, and the menu host in `scripts/` for seeing the D-Bus path work
44
+ on a desktop that has none.
45
+ - [events.md](events.md) — the synthetic event system: dispatch phases,
46
+ event object shape, focus, cursors, default actions.
47
+ - [accessibility.md](accessibility.md) — screen readers see react-x11 apps:
48
+ the built-in AT-SPI2 bridge, the standard `role`/`aria-*` props on every
49
+ element, what the defaults already say, what each widget announces,
50
+ `announce()`, driving controls from assistive technology, the no-bus
51
+ compatibility ladder, and how to test all of it without a desktop. The
52
+ design record behind it — no mirror tree, the event pipeline, what was
53
+ rejected — is
54
+ [architecture/accessibility.md](architecture/accessibility.md).
55
+ - [react-features.md](react-features.md) — what your React knowledge buys
56
+ you here and where a DOM habit breaks: `useLayoutEffect` vs `useEffect`,
57
+ measuring a node without `getBoundingClientRect()`, what a `ref` hands
58
+ back, `<popup>` instead of `createPortal`, where to put an error boundary
59
+ so the window survives, and which React APIs are simply not available.
60
+ - [drag-and-drop.md](drag-and-drop.md) — accepting drops and starting
61
+ drags, over XDND and in-app: `dropAccept` matching, the payload
62
+ (`e.files`, `e.getData`, live `e.items`), `dragData` and lazy payloads,
63
+ the `useDropTarget`/`useDragSource` hooks, drag previews, what GTK and
64
+ Firefox actually offer, and how to drive a drag in a test.
65
+ - [clipboard.md](clipboard.md) — copy and paste beyond the built-in text
66
+ controls: `useClipboard()`, the CLIPBOARD/PRIMARY split, offering several
67
+ flavours of one payload, the `text`/`files`/`uris` groups shared with drag
68
+ and drop, `watch()`, and why a copy carries a timestamp — and what the
69
+ pasteboard does differently on macOS.
70
+ - [typescript.md](typescript.md) — the bundled types: one tsconfig option,
71
+ why JSX comes from `react-x11/jsx-runtime` rather than an augmentation,
72
+ and how the declarations are kept from drifting.
73
+ - [extending.md](extending.md) — `registerElement()` and the subpath
74
+ exports: adding a host element from outside the package, the node
75
+ contract, the two definition fields that fail far from their cause, and
76
+ the damage seam an element that draws a whole scene reads and claims.
77
+ - [gl.md](gl.md) — `<glarea>`, a GL surface in the layout, and the three
78
+ ways underneath it: indirect GLX, the direct GPU backend, and CGL into a
79
+ layer on Cocoa. `glPolicy`, what each can draw, `<shaderMaterial>` — GLSL
80
+ with three.js's names — and `<effectComposer>` post-processing, both on
81
+ the direct ones.
82
+ - [glx.md](glx.md) — how a 3D scene works over indirect GLX: what the
83
+ protocol encodes, why display lists are mandatory, and what can never work.
84
+ - [embedding.md](embedding.md) — `<foreign>`: another application's window
85
+ inside yours. XEmbed and the plain-reparent path most clients actually
86
+ want, why unmount hands the window back rather than destroying it, and
87
+ the rule that keeps an app's chords from being swallowed by the client.
88
+ **X11 only** — cross-process window embedding does not exist on macOS.
89
+ - [frame.md](frame.md) — `<Frame>`: a pane of your own application in a
90
+ process of its own, embedded and laid out like any other child. What the
91
+ process boundary buys (parallelism, crash and leak isolation), what it
92
+ does not (it is not a security boundary), and the two ways it is realized
93
+ — a `<foreign>` window on X11, shared IOSurfaces on Cocoa.
94
+ - [testing.md](testing.md) — `react-x11/test`: render, query, drive and
95
+ assert on real pixels, against a real X server in your test process. No
96
+ display, no xvfb — and no Cocoa: the harness drives the **X11** backend.
97
+ - [desktop.md](desktop.md) — what an app tells the desktop about itself
98
+ beyond drawing. Startup notification: why the launcher's busy cursor spins
99
+ for 15 seconds without it, when an app counts as "started", and the seams
100
+ for saying otherwise.
101
+ - [dbus.md](dbus.md) — the bus every desktop-integration feature sits on:
102
+ `useSessionBus()` / `useSystemBus()` with nothing to wrap, the imperative
103
+ `sessionBus()` pair underneath, why one process is one connection and one
104
+ identity, and why "there is no bus" is a first-class configuration rather
105
+ than an error.
106
+ - [uri-schemes.md](uri-schemes.md) — being the app a `myapp://…` link opens:
107
+ `registerApplication()` and the two dispatch paths a real desktop uses (only
108
+ one of which is D-Bus), why a second copy of the app has to forward and
109
+ exit, `useAppOpen()`, and the timestamp without which the window does not
110
+ actually come forward. Also: why a loopback port is the better answer for a
111
+ login, and the `.desktop` half that is an install step rather than code.
112
+ - [filedialog.md](filedialog.md) — open, save and pick a folder:
113
+ `useFileDialog()`, the four-rung ladder (a native panel on the cocoa
114
+ backend, the desktop's own portal, `osascript` under XQuartz, a browser
115
+ react-x11 draws itself), why cancelling is
116
+ `null` rather than a throw, and the places the backends genuinely differ.
117
+ - [permissions.md](permissions.md) — may the app use the camera, the
118
+ microphone, the screen, the accessibility APIs: `usePermission()`, the
119
+ five-word status vocabulary (`'unknown'` is the machine's answer, not the
120
+ permission's), the cocoa backend's TCC rung and the Settings-pane rung any
121
+ Mac has, and why Linux answers `'unknown'` until the device portals land.
122
+ - [notifications.md](notifications.md) — a banner outside the app's own
123
+ windows: `notify()` and `useNotifier()`, the four-rung ladder (the cocoa
124
+ backend's notification centre, `org.freedesktop.Notifications`,
125
+ `osascript`, `notify-send`), updating a banner in place, what the user
126
+ did with it, and why the shell-out rungs cannot report back.
127
+ - [desktop-calendar.md](desktop-calendar.md) — the user's real events, with
128
+ no credential and no OAuth: `useDesktopCalendarEvents()`, the three-rung
129
+ ladder (EventKit through the bridge, EventKit through an `osascript` child,
130
+ Evolution Data Server over the bus), why `end` is exclusive everywhere, and
131
+ why `'denied'` and `'unavailable'` are different words.
132
+ - [eyedropper.md](eyedropper.md) — sample a colour from the screen:
133
+ `useEyedropper()`/`pickScreenColor()`, the three-rung ladder (macOS's
134
+ `NSColorSampler`, the portal's own picker, a crosshair grab on plain X11),
135
+ the interface `version` property that gates the portal rung where
136
+ `hasService()` cannot, and why the grab's whole lifecycle — including the
137
+ `<popup grab>` it displaces — belongs to core.
138
+ - [appearance.md](appearance.md) — light or dark, the accent colour,
139
+ contrast and reduced motion: `useSystemAppearance()`, `<ThemeProvider dark>`
140
+ for apps that only want to follow the desktop, why the answer is remembered
141
+ on disk so the first frame is not a flash, and what each rung of the ladder
142
+ can actually answer.
143
+ - [scale.md](scale.md) — HiDPI: every length you write is a logical pixel,
144
+ `createRoot({ scale: 'auto' })` resolves how many device pixels one is
145
+ worth (environment → XSETTINGS/`Xft.dpi` → audited RandR millimetres →
146
+ the resolution class), `useScale()`, per-monitor answers on
147
+ `useScreens()`, and why a virtual machine's EDID needs the audit.
148
+ - [system.md](system.md) — the machine around the app: `useScreens()` for the
149
+ monitor layout, `useWindowState()` for what the window manager actually did,
150
+ `useIdle()`/`useKeepAwake()`, `useKeyboardState()` for Caps Lock and the live
151
+ layout, `useDesktopSettings()` for the timings the built-in controls already
152
+ follow, and `useLocale()`. Also what each one answers on a display with the
153
+ extension missing, and why `obscured` is always false under a compositor.
154
+ - [remote.md](remote.md) — the flagship case: running the app on one
155
+ machine and drawing to a display on another. `ssh -X` vs `-Y`, what the
156
+ protocol costs on a link, the other X servers, and why Xwayland works
157
+ where native Wayland structurally cannot.
158
+ - [wayland.md](wayland.md) — the research RFC for a native Wayland
159
+ backend: a second target beside X11, not a migration. What the protocol
160
+ actually changes, the fd transport (why the prototype is Bun-first), the
161
+ rendering tiers from a pure-JS span compositor to GPU 2d over x11-dri,
162
+ what maps and what is gone by design, and the phased plan.
163
+ - [wayland-backend.md](wayland-backend.md) — the Wayland backend as built:
164
+ GLES over dma-buf into a backing target, xdg-shell with deferred acks,
165
+ client-side decorations, the XKB keymap reader, the in-process test
166
+ compositor; what was measured (the protocol layer is not the cost, and
167
+ no native protocol bridge was built), and what is still open.
168
+ - [windows-integrations.md](windows-integrations.md) — what an app on
169
+ Windows can actually reach, measured rather than inferred: the table of
170
+ what works, the gaps that cost an app something today (drag and drop, IME,
171
+ UI Automation) with the route for each, the integrations that are blocked
172
+ on package identity rather than missing, and the things Windows has that
173
+ no other desktop does.
174
+ - [windows.md](windows.md) — the design record behind it, written as a PRD
175
+ before any of it existed. Where Windows
176
+ sits between the Wayland and macOS inversions (the client rasterizes, into
177
+ retained composition surfaces that keep the damage model intact), a UI
178
+ thread of the addon's own so that Windows' modal loops never freeze JS,
179
+ Direct2D and DirectWrite behind the contracts the Cocoa backend already
180
+ proved, why the bridge is our own mechanism-only addon rather than
181
+ anything on npm, what maps and what is gone, the phased plan, and what to
182
+ probe first on a Windows machine.
183
+ - [security.md](security.md) — the threat model, plainly: X11 has no
184
+ isolation between clients, `$XAUTHORITY` is a password, and what
185
+ react-x11 does and does not defend against.
186
+ - [packaging.md](packaging.md) — five ways to ship an app, the esbuild flags
187
+ that are load-bearing, and the two macOS distribution tracks: Developer ID
188
+ takes node or bun, the App Store's sandbox takes node only.
189
+ - [devtools.md](devtools.md) — React DevTools integration and other
190
+ debugging aids.
191
+ - [debugging.md](debugging.md) — runtime diagnostics: protocol tracing
192
+ (`REACT_X11_TRACE`, `startTrace()`), repaint flashing and full-repaint
193
+ warnings (`REACT_X11_DEBUG_PAINT`), invalidation reasons.
194
+ - [click-to-component.md](click-to-component.md) — Alt+Click a rendered
195
+ element to open its JSX source line in your editor.
196
+ - [ecosystem.md](ecosystem.md) — which npm packages work with react-x11 and
197
+ which do not: the rule that decides it, a compatibility table across 12
198
+ categories, and a register of the verbatim errors the incompatible ones
199
+ produce. Per-category pages:
200
+ [state](ecosystem/state.md), [data fetching](ecosystem/data-fetching.md),
201
+ [forms](ecosystem/forms.md), [icons](ecosystem/icons.md),
202
+ [theming](ecosystem/theming.md), [animation](ecosystem/animation.md),
203
+ [headless components](ecosystem/headless.md),
204
+ [layout](ecosystem/layout.md), [routing](ecosystem/routing.md),
205
+ [i18n](ecosystem/i18n.md), [testing](ecosystem/testing.md),
206
+ [dev tooling](ecosystem/dev-tooling.md).
207
+
208
+ ## Design records
209
+
210
+ `architecture/` holds the documents behind the bigger pieces: measured,
211
+ written against a named commit, and kept as the record of _why_ rather than
212
+ the reference for _what_. Some describe what shipped; some are proposals
213
+ that have not been built, and say so at the top.
214
+
215
+ - [architecture/frame-pacing.md](architecture/frame-pacing.md) — the
216
+ design record behind `frameRate`: why a window fed off an input path
217
+ paints screens nobody sees, the token bucket over paint time that holds
218
+ it to a budget, where it lives on both backends, and what it measured.
219
+ - [architecture/element-layer-contents.md](architecture/element-layer-contents.md)
220
+ — the design record for the other half of a streaming element's frame on
221
+ macOS: why an element with a retained surface pays a composite and the
222
+ window swapchain's catch-up copy to move pixels it already has, what the
223
+ platform does with an element-owned IOSurface (spiked in pixels), and the
224
+ presentable `Surface` plus `presentedSurface()` policy that would remove
225
+ both. Not built.
226
+ - [architecture/video.md](architecture/video.md) — the design record for
227
+ video, reviewed against the four backends: why no X11 extension decodes
228
+ anything and the one that did is dead, what a decoded frame costs through
229
+ core `PutImage` and what Xv would change, the VideoToolbox and Core
230
+ Animation ladder on macOS measured end to end, the YUV surface that is
231
+ blank through `render(in:)` and drawn on screen (probed, and it reverses
232
+ the first version's Cocoa design), what a frame sink costs through a
233
+ plain layer, the Media Foundation plan for Windows with the probes it
234
+ owes, a `<video>` element with two sources — `frames` everywhere, `src`
235
+ where the platform has a player — on the sprite seam, and how `<Html>`
236
+ and `<MediaPlayer>` consume it. Not built.
237
+ - [architecture/animation.md](architecture/animation.md) — what the style
238
+ vocabulary cannot say today (a fade, a move that does not reflow, a
239
+ timeline that ends), who should interpolate it, and what offloading a
240
+ transition to Core Animation costs and buys.
241
+ - [architecture/container-queries.md](architecture/container-queries.md) —
242
+ why a container's size is an output of layout where a window's is an
243
+ input, the resolve-after-a-pass loop that follows, and the oscillation it
244
+ can produce. Implemented; [styling.md](styling.md#container-queries) is
245
+ the reference.
246
+ - [architecture/custom-layout.md](architecture/custom-layout.md) — why an
247
+ arrangement that depends on a layout output has to run inside the pass
248
+ rather than in an effect, the two seams that do — a `layout` that arranges
249
+ a box's children and a `position` that moves one node, with `sticky` now
250
+ the built-in one — how a layout's children become yoga trees of their own,
251
+ and what they cost. Implemented; [styling.md](styling.md#custom-layouts)
252
+ is the reference.
253
+ - [architecture/grid-layout.md](architecture/grid-layout.md) — CSS Grid as
254
+ a layout on that seam, written the way CSS writes it (`display: 'grid'`,
255
+ `gridTemplateColumns`): why the style is flat, the spec's placement and
256
+ track sizing and what is left out, how it is held to Chrome, and what it
257
+ costs against flexbox — more than it should have, until the seam
258
+ remembered what it asks a child. Implemented;
259
+ [styling.md](styling.md#grid) is the reference.
260
+ - [architecture/drag-and-drop.md](architecture/drag-and-drop.md) — XDND on
261
+ both sides: where the advertisement lives when every control is drawn into
262
+ one window, what the drag-source half costs, and the API review that
263
+ produced the one in [drag-and-drop.md](drag-and-drop.md).
264
+ - [architecture/accessibility.md](architecture/accessibility.md) — the
265
+ AT-SPI2 bridge with no mirror tree: what it exposes, the event pipeline,
266
+ and the alternatives that lost.
267
+ - [architecture/protocol-efficiency.md](architecture/protocol-efficiency.md)
268
+ — a request-by-request audit of one hovered checkbox, across react-x11,
269
+ ntk and node-x11, and the fixes it produced.
270
+ - [architecture/windowed-regions.md](architecture/windowed-regions.md) —
271
+ when an X11 subwindow pays for itself and when it does not, measured
272
+ against three servers. Research; nothing here is built.
273
+
274
+ ## Entry points
275
+
276
+ ```js
277
+ import { createRoot, Select } from 'react-x11';
278
+ ```
279
+
280
+ ### `await createRoot(options?)` → `{ app, render(element), unmount() }`
281
+
282
+ The entry point. With no options it opens a connection to whichever backend
283
+ this machine has: the **Cocoa** bridge on macOS, or the X server named by
284
+ `$DISPLAY`. On a Mac without `@windowkit/appkit` installed it falls back to
285
+ X11, once and out loud, so an XQuartz setup keeps working. The returned
286
+ `app` is that backend's app object — the [ntk](https://github.com/sidorares/ntk)
287
+ App and its one X connection on X11.
288
+
289
+ **Every root without `app` opens its own connection and owns it**, so two
290
+ roots are two independent trees, and `await root.unmount()` closes what it
291
+ opened — without which the socket stays up and the process does not exit.
292
+ A root given an `app` borrows it and never closes it: that connection
293
+ belongs to whoever made it.
294
+
295
+ One thing to know about `'auto'` before it surprises you: on macOS it
296
+ answers Cocoa, and **`$DISPLAY` in the environment does not change that.**
297
+ Naming an X endpoint _in code_ — `display` or `stream` — does, because an
298
+ ignored connection option would be worse than either answer; from the
299
+ environment, say `REACT_X11_BACKEND=x11`. See
300
+ [remote.md](remote.md) for the case this actually comes up in.
301
+
302
+ | option | |
303
+ | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
304
+ | `backend` | `'auto'` (default), `'x11'` or `'cocoa'`. Naming `'cocoa'` makes the bridge required rather than preferred |
305
+ | `app` | render into a connection you already have — the option a backend choice is ignored for |
306
+ | `cocoa` | that backend's knobs: `presenter`, `promote`, `frameInterval`, `pumpInterval`, `appName`, `activationPolicy`, `exitOnQuit` ([macos.md](macos.md)) |
307
+ | `scale` | device pixels per logical pixel: `'auto'` (default) or a number ([scale.md](scale.md)) |
308
+ | `frameRate` | how windows pace frames under a flood: `'display'` (default) or `'adaptive'` ([elements.md](elements.md#framerate--pacing-the-frames-under-a-flood)) |
309
+ | `desktop` | `false`, or `{ appearance, a11y, globalMenu }` — the three things that dial the session bus ([desktop.md](desktop.md)) |
310
+ | `startupNotification` | freedesktop startup notification, on by default; `false`, or the id ([desktop.md](desktop.md)) |
311
+ | `compose` | dead keys and Compose: the built-in table by default, `'system'`, `{ file }`/`{ sequences }`, or `false` |
312
+ | `accelerators` | which keysym a shortcut matches: `'latin'` (default), `'layout'`, or a table |
313
+ | `restoreFocusOnReveal` | whether a revealed subtree takes the keyboard back. Default `true` |
314
+ | `textStripBelow` | the size under which `<text>` paints as a strip of ink rather than glyphs. Default 6; `0` never |
315
+ | `display` | **X11.** `':1'`, `'host:0.0'`, a socket path. Default `$DISPLAY`. Naming one chooses the X11 backend |
316
+ | `stream` | **X11.** an already-connected duplex stream — also a backend choice |
317
+ | `fontSource` | **X11.** pluggable system-font lookup — ntk's docs/fonts.md |
318
+ | `glPolicy` `glxVisual` | **X11.** which GL backend `<glarea>` draws through, and a visual for it ([gl.md](gl.md)) |
319
+ | `onXError` | **X11.** protocol errors nothing claimed. Default warns |
320
+ | `onUncaughtError` `onCaughtError` `onRecoverableError` | `(error, errorInfo)`; default logs the component stack |
321
+ | `onDisconnect(reason, err)` | **X11.** the connection ended — `'closed'` or `'error'` |
322
+
323
+ `display`, `stream`, `fontSource`, `glxVisual`, `glPolicy` and `onXError` go
324
+ straight to ntk's `createClient`. Anything else it understands, build the
325
+ client yourself and pass it as `app` — which is also how the hermetic tests
326
+ drive the renderer against node-x11's in-process X server:
327
+
328
+ ```js
329
+ import xserver from 'x11/lib/xserver/index.js';
330
+
331
+ const server = xserver.createServer({ width: 640, height: 480 });
332
+ const [serverEnd, clientEnd] = xserver.createStreamPair();
333
+ server.addClientStream(serverEnd);
334
+ const root = await createRoot({ stream: clientEnd }); // no $DISPLAY needed
335
+ ```
336
+
337
+ `onUncaughtError` covers one channel React does not: a throw from an **event
338
+ handler**, which no error boundary can catch because the handler ran from an
339
+ input event rather than a render. See
340
+ [events.md](events.md#when-a-handler-throws).
341
+
342
+ `onDisconnect` fires when an X connection ends without being asked to —
343
+ server exit, ssh drop, kill — and not for one this root closed. It invites
344
+ a reconnect loop, so: **a reconnect is not a reconnect.** Every window id,
345
+ pixmap, glyph set and font is invalidated with the connection. Tear the
346
+ root down and build a new one; nothing survives, and react-x11 promises
347
+ nothing more than telling you it happened.
348
+
349
+ `root.render(element, callback?)` flushes the mount or update synchronously
350
+ (`updateContainerSync` + `flushSyncWork`); painting happens a frame later on
351
+ the window's frame clock.
352
+
353
+ ## Environment variables
354
+
355
+ Every one of these has an option or a prop that says the same thing in code;
356
+ the variable exists for the cases where you cannot edit the call — someone
357
+ else's app, a `.desktop` launcher, an A/B run. `npx react-x11 help` prints
358
+ every one the renderer reads, the diagnostic switches included, grouped and
359
+ with what each does.
360
+
361
+ **Choosing a backend and a display**
362
+
363
+ | variable | effect |
364
+ | ---------------------------- | ------------------------------------------------------------------------ |
365
+ | `DISPLAY` | X server to connect to (standard X11) |
366
+ | `REACT_X11_BACKEND` | `x11`, `cocoa` or `wayland`, overriding `backend` and the default |
367
+ | `REACT_X11_GL_DEVICE` | Wayland: the DRM node to render on, where `glPolicy.devicePath` is unset |
368
+ | `REACT_X11_SCALE` | device pixels per logical pixel; outranks even a pinned `scale` number |
369
+ | `REACT_X11_FRAME_RATE` | `display` or `adaptive`, overriding `frameRate` and the props |
370
+ | `REACT_X11_TEXT_STRIP_BELOW` | the `textStripBelow` size, for a process that cannot pass the option |
371
+
372
+ **Turning desktop integration off**
373
+
374
+ | variable | effect |
375
+ | ----------------------------- | --------------------------------------------------------------------- |
376
+ | `REACT_X11_A11Y` | set at all: log why the AT-SPI bridge did not start. `0` turns it off |
377
+ | `NO_AT_BRIDGE=1` | the freedesktop spelling of the same off switch |
378
+ | `REACT_X11_NO_GLOBAL_MENU=1` | `MenuBar` always draws its own bar |
379
+ | `REACT_X11_NO_TRANSPARENCY=1` | pretend there is no compositor ([debugging.md](debugging.md)) |
380
+
381
+ **Development and diagnostics**
382
+
383
+ | variable | effect |
384
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
385
+ | `REACT_X11_DEVTOOLS=1` | connect to a running `react-devtools` (see devtools.md); on by default under `react-x11 dev`, `=0` turns it off |
386
+ | `REACT_X11_DEVTOOLS_HOST` | devtools host (default `localhost`) |
387
+ | `REACT_X11_DEVTOOLS_PORT` | devtools port (default `8097`) |
388
+ | `REACT_X11_DEBUG_LAYOUT=1` | outline every laid-out node, color-coded by tree depth |
389
+ | `REACT_X11_DEBUG_PAINT=1` | stroke each frame's damage rects in a rotating colour; `=full` also warns on full-window repaints |
390
+ | `REACT_X11_TRACE` | record the X11 protocol — see [debugging.md](debugging.md) for the grammar |
391
+ | `REACT_X11_CLICK_TO_COMPONENT=1` | Alt+Click opens the clicked element's source, using `cursor` (see click-to-component.md); on by default under `react-x11 dev`, `=0` turns it off |
392
+ | `REACT_X11_EDITOR` | editor CLI for click-to-component — setting this alone also enables it |
393
+ | `REACT_X11_STRICT_TOKENS=1` | a `$token` the theme does not define is fatal instead of dropped |
394
+
395
+ **The Cocoa backend**
396
+
397
+ | variable | effect |
398
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
399
+ | `REACT_X11_COCOA_PRESENTER` | `surface` (the measured default) or `layers` |
400
+ | `REACT_X11_COCOA_PROMOTE` | `1`/`0`, forcing layer promotion on or off |
401
+ | `REACT_X11_COCOA_PANE_STRETCH` | `behind` (default), `never` or `always`: when a `<Frame>` pane's last frame is stretched while a resize waits on the next ([frame.md](frame.md)) |
402
+ | `REACT_X11_CALAYERS_PATH` | load the bridge from a checkout or an extracted tarball instead of the package |
403
+
404
+ There are a handful more that exist only to switch off one optimisation
405
+ while measuring it — `REACT_X11_NO_PAINT_CACHE`, `REACT_X11_NO_SCROLL_BLIT`,
406
+ `REACT_X11_NO_PANE_SHAPE`,
407
+ `REACT_X11_NO_BOUNDS_CACHE`, `REACT_X11_NO_STROKE_CHUNKING`,
408
+ `REACT_X11_NO_SCOPED_FLOORS`, `REACT_X11_NO_UNREAD_WIDTHS`,
409
+ `REACT_X11_NO_REFIT_HOLD`, `REACT_X11_NO_APPEARANCE_CACHE`. They are development instruments, not API,
410
+ and they are documented where the thing they disable is.