react-x11 2.51.1 → 2.53.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 (121) hide show
  1. package/README.md +94 -61
  2. package/docs/README.md +256 -0
  3. package/docs/accessibility.md +575 -0
  4. package/docs/appearance.md +317 -0
  5. package/docs/click-to-component.md +92 -0
  6. package/docs/clipboard.md +262 -0
  7. package/docs/components.md +1231 -0
  8. package/docs/dbus.md +205 -0
  9. package/docs/debugging.md +371 -0
  10. package/docs/desktop-calendar.md +247 -0
  11. package/docs/desktop.md +523 -0
  12. package/docs/devtools.md +133 -0
  13. package/docs/drag-and-drop.md +585 -0
  14. package/docs/ecosystem/animation.md +360 -0
  15. package/docs/ecosystem/data-fetching.md +186 -0
  16. package/docs/ecosystem/dev-tooling.md +393 -0
  17. package/docs/ecosystem/forms.md +277 -0
  18. package/docs/ecosystem/headless.md +194 -0
  19. package/docs/ecosystem/i18n.md +86 -0
  20. package/docs/ecosystem/icons.md +377 -0
  21. package/docs/ecosystem/layout.md +206 -0
  22. package/docs/ecosystem/routing.md +135 -0
  23. package/docs/ecosystem/state.md +344 -0
  24. package/docs/ecosystem/testing.md +474 -0
  25. package/docs/ecosystem/theming.md +494 -0
  26. package/docs/ecosystem.md +439 -0
  27. package/docs/elements.md +2079 -0
  28. package/docs/embedding.md +239 -0
  29. package/docs/events.md +742 -0
  30. package/docs/extending.md +1700 -0
  31. package/docs/eyedropper.md +164 -0
  32. package/docs/filedialog.md +222 -0
  33. package/docs/frame.md +436 -0
  34. package/docs/gl.md +173 -0
  35. package/docs/globalmenu.md +195 -0
  36. package/docs/macos.md +592 -0
  37. package/docs/notifications.md +150 -0
  38. package/docs/packaging.md +468 -0
  39. package/docs/permissions.md +143 -0
  40. package/docs/react-features.md +405 -0
  41. package/docs/remote.md +179 -0
  42. package/docs/scale.md +225 -0
  43. package/docs/security.md +132 -0
  44. package/docs/styling.md +1710 -0
  45. package/docs/system.md +519 -0
  46. package/docs/testing.md +494 -0
  47. package/docs/typescript.md +75 -0
  48. package/docs/uri-schemes.md +340 -0
  49. package/docs/wayland-backend.md +332 -0
  50. package/docs/windows-integrations.md +177 -0
  51. package/docs/windows.md +380 -0
  52. package/package.json +11 -3
  53. package/src/Reconciler.js +2 -2
  54. package/src/a11y.js +1 -1
  55. package/src/backend/context2d.js +3 -3
  56. package/src/bootstrap.js +1 -1
  57. package/src/bus.js +39 -26
  58. package/src/cli/create.d.ts +43 -0
  59. package/src/cli/create.js +305 -0
  60. package/src/cli/env.js +484 -0
  61. package/src/cli/index.js +29 -2
  62. package/src/cli/templates/AGENTS.template.md +195 -0
  63. package/src/cli/templates/DESIGN.template.md +269 -0
  64. package/src/cocoa/app.js +6 -6
  65. package/src/cocoa/bezels.js +1 -1
  66. package/src/cocoa/fonts.js +1 -1
  67. package/src/cocoa/globalmenu.js +1 -1
  68. package/src/cocoa/keymap.js +1 -1
  69. package/src/cocoa/panewindow.js +1 -1
  70. package/src/cocoa/player.js +1 -1
  71. package/src/cocoa/presenter.js +2 -2
  72. package/src/cocoa/promotion.js +1 -1
  73. package/src/cocoa/relaunch.js +1 -1
  74. package/src/cocoa/threaded.js +1 -1
  75. package/src/cocoa/video.js +1 -1
  76. package/src/cocoa/window.js +4 -4
  77. package/src/components/Menu.js +7 -2
  78. package/src/components/Switch.js +1 -1
  79. package/src/components/native.js +1 -1
  80. package/src/desktopintegration.js +2 -1
  81. package/src/desktopsettings.js +193 -24
  82. package/src/dnd.js +2 -2
  83. package/src/filedialog.js +3 -3
  84. package/src/glnodes.js +1 -1
  85. package/src/grid.js +1 -1
  86. package/src/keyboardstate.js +28 -0
  87. package/src/layouts.js +1 -1
  88. package/src/node.d.ts +10 -10
  89. package/src/nodes/animation.js +1 -1
  90. package/src/nodes/invalidate.js +1 -1
  91. package/src/nodes/layouthost.js +1 -1
  92. package/src/nodes/video.js +19 -8
  93. package/src/nodes/window/droptarget.js +1 -1
  94. package/src/pacing.js +1 -1
  95. package/src/portal.js +31 -0
  96. package/src/refresh/index.js +2 -1
  97. package/src/screencolor.js +5 -10
  98. package/src/types/system.d.ts +8 -6
  99. package/src/types/video.d.ts +5 -2
  100. package/src/videobackend.js +28 -0
  101. package/src/videoframes.js +29 -16
  102. package/src/wayland/app.js +86 -0
  103. package/src/wayland/clipboard.js +14 -7
  104. package/src/wayland/connection.js +3 -0
  105. package/src/wayland/context2d.js +129 -10
  106. package/src/wayland/protocols/index.json +6 -0
  107. package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
  108. package/src/wayland/seat.js +28 -1
  109. package/src/wayland/swapchain.js +23 -0
  110. package/src/wayland/video.js +376 -0
  111. package/src/wayland/xkb.js +137 -0
  112. package/src/win32/a11y.js +1 -1
  113. package/src/win32/app.js +2 -2
  114. package/src/win32/fonts.js +1 -1
  115. package/src/win32/glarea.js +4 -4
  116. package/src/win32/overlay.js +1 -1
  117. package/src/win32/panewindow.js +3 -3
  118. package/src/win32/shell.js +1 -1
  119. package/src/win32/window.js +2 -2
  120. package/src/windowid.js +1 -1
  121. package/src/xvideo.js +189 -0
@@ -0,0 +1,439 @@
1
+ # Ecosystem
2
+
3
+ react-x11 is a React renderer with no DOM: no `document`, no `window`
4
+ global, no CSSOM, and the host elements are `<box>`/`<text>`/`<svg>`, not
5
+ `<div>`/`<span>`. A package that only touches React — hooks, context, state,
6
+ reconciliation — works unchanged; one that reaches for `document`, `window`,
7
+ `HTMLElement`, CSS, or renders a `<div>` does not.
8
+
9
+ That rule decides every verdict below. Each was established by running the
10
+ library against react-x11 1.2.0, not by reading its documentation; React
11
+ DevTools and Fast Refresh, which react-x11 wires up itself, are documented as
12
+ working setups instead.
13
+
14
+ ## The 30-second test
15
+
16
+ Before installing anything, ask four questions in order. Each has a command.
17
+
18
+ 1. **Does it import?** `node --input-type=module -e "import('the-package')"`.
19
+ A package that hard-requires `react-dom`, or whose `exports` map has only
20
+ browser conditions, fails here ([import time](#install-and-import-time)).
21
+ If something else in your tree already pulled in `react-dom`, this passes
22
+ and the problem moves to the [silent](#silent-failures) column — run
23
+ `npm ls react-dom` before you trust a pass.
24
+ 2. **Does it render host elements?** Grep the shipped code for tag names:
25
+
26
+ ```sh
27
+ grep -rEoh '"(div|span|button|input|form|style|a)"' \
28
+ node_modules/the-package --include='*.js' --include='*.mjs' | sort -u
29
+ ```
30
+
31
+ Anything that emits DOM tags cannot render here, however headless the
32
+ README says it is. This one is a reliable verdict: zustand and
33
+ `@tanstack/react-table` print nothing; recharts, react-select and Headless
34
+ UI print a list.
35
+
36
+ 3. **Does it read DOM globals?** Same shape, different pattern:
37
+
38
+ ```sh
39
+ grep -rnE 'typeof window|typeof document|HTMLElement|getBoundingClientRect' \
40
+ node_modules/the-package --include='*.js' --include='*.mjs'
41
+ ```
42
+
43
+ A pointer, not a verdict — _read the hits_. A minified UMD bundle or an
44
+ `isSSR = typeof window === "undefined"` default matches harmlessly. Look
45
+ for an environment probe whose result gates a feature: that is the
46
+ silent-failure shape, where the library decides it is doing SSR and
47
+ quietly turns things off. Check the transitive core too —
48
+ `@tanstack/query-core`, not just `@tanstack/react-query`, which has no
49
+ hits of its own.
50
+
51
+ 4. **Does it expect DOM-shaped events?** Usually fine: `<textinput onChange>`
52
+ passes a synthetic event with `target.value` (writable) and `target.name`,
53
+ so `event.target.value` reads as it does in the DOM. Check the
54
+ **opposite** direction: a library whose field contract is
55
+ value-in/value-out (`field.handleChange(value)`) needs one unwrap per
56
+ field, and a bare `onChange={field.handleChange}` stores the event object
57
+ with no error. Grep your own code for `onChange={` on a `<textinput>`.
58
+
59
+ A library that passes all four is almost always a drop-in. One that fails 2
60
+ or 3 usually has a headless core published separately — the pattern behind
61
+ half the adapters on this page.
62
+
63
+ ## What works
64
+
65
+ Fifty-five packages and two Node built-ins, across 12 categories. **Out of
66
+ the box** means install and use; **adapter** means a little glue, written
67
+ out in full on the category page.
68
+
69
+ ### State management
70
+
71
+ | Package | Integration | |
72
+ | -------------------------------------------- | ---------------------------------------------------- | ----------------------------------- |
73
+ | `zustand` | out of the box | [state](ecosystem/state.md#zustand) |
74
+ | `jotai` | out of the box | [state](ecosystem/state.md#jotai) |
75
+ | `valtio` | out of the box | [state](ecosystem/state.md#valtio) |
76
+ | `xstate` + `@xstate/react` | out of the box | [state](ecosystem/state.md#xstate) |
77
+ | `redux` + `@reduxjs/toolkit` + `react-redux` | out of the box — **pin react-redux ≥ 9** | [state](ecosystem/state.md#redux) |
78
+ | `immer` | out of the box | [state](ecosystem/state.md#immer) |
79
+ | `mobx` + `mobx-react-lite` | adapter — no code, but `react-dom` must be installed | [state](ecosystem/state.md#mobx) |
80
+
81
+ ### Data fetching
82
+
83
+ | Package | Integration | |
84
+ | ----------------------- | ------------------ | ---------------------------------------------------------- |
85
+ | `@tanstack/react-query` | adapter, ~12 lines | [data fetching](ecosystem/data-fetching.md#tanstack-query) |
86
+ | `swr` | adapter, 1 line | [data fetching](ecosystem/data-fetching.md#swr) |
87
+
88
+ ### Forms and validation
89
+
90
+ | Package | Integration | |
91
+ | ---------------------- | ---------------------------------------------------------- | ------------------------------------------- |
92
+ | `@tanstack/react-form` | out of the box | [forms](ecosystem/forms.md#tanstack-form) |
93
+ | `zod` | out of the box | [forms](ecosystem/forms.md#zod) |
94
+ | `react-hook-form` | out of the box — `register()` or `<Controller>` | [forms](ecosystem/forms.md#react-hook-form) |
95
+ | `formik` | out of the box — no `<Form>`; `<Field>` with a render prop | [forms](ecosystem/forms.md#formik) |
96
+ | `downshift` | out of the box — `getInputProps()` on a `<textinput>` | [forms](ecosystem/forms.md) |
97
+
98
+ ### Icons
99
+
100
+ | Package | Integration | |
101
+ | ------------------------------------ | ------------------------------------- | -------------------------------------------- |
102
+ | `@iconify/utils` + `@iconify-json/*` | out of the box | [icons](ecosystem/icons.md#iconify) |
103
+ | `@heroicons/react` | out of the box — size it with `style` | [icons](ecosystem/icons.md#heroicons-react) |
104
+ | `lucide` | adapter, ~10 lines | [icons](ecosystem/icons.md#lucide) |
105
+ | `lucide-static` | adapter, ~12 lines (`iconSource`) | [icons](ecosystem/icons.md#lucide-static) |
106
+ | `react-icons` | adapter, ~15 lines | [icons](ecosystem/icons.md#react-icons) |
107
+ | `@tabler/icons` | adapter — `iconSource` | [icons](ecosystem/icons.md#tabler-icons) |
108
+ | `@phosphor-icons/core` | adapter — `iconSource` | [icons](ecosystem/icons.md#phosphor-icons) |
109
+ | `heroicons` (the asset package) | adapter — `iconSource` | [icons](ecosystem/icons.md#heroicons-assets) |
110
+ | `feather-icons` | adapter, ~5 lines | [icons](ecosystem/icons.md#feather-icons) |
111
+
112
+ ### Theming, palettes and colour
113
+
114
+ | Package | Integration | |
115
+ | ------------------------------------- | ----------------------------------- | -------------------------------------------------------- |
116
+ | `@radix-ui/colors` | out of the box | [theming](ecosystem/theming.md#radix-colors) |
117
+ | `@catppuccin/palette` | out of the box | [theming](ecosystem/theming.md#catppuccin) |
118
+ | `@material/material-color-utilities` | out of the box from a source colour | [theming](ecosystem/theming.md#material-color-utilities) |
119
+ | `colord` | out of the box | [theming](ecosystem/theming.md#colord) |
120
+ | `culori` | out of the box | [theming](ecosystem/theming.md#culori) |
121
+ | `open-props` | out of the box for colours | [theming](ecosystem/theming.md#open-props) |
122
+ | `tailwindcss` (`/colors` export only) | adapter, ~3 lines — oklch → hex | [theming](ecosystem/theming.md#tailwind-colors) |
123
+ | `daltonize` | adapter, ~4 lines | [theming](ecosystem/theming.md#daltonize) |
124
+
125
+ ### Animation
126
+
127
+ | Package | Integration | |
128
+ | ---------------------------------- | --------------------------------- | ---------------------------------------------------------- |
129
+ | `popmotion` | out of the box | [animation](ecosystem/animation.md#popmotion) |
130
+ | `d3-ease` | out of the box | [animation](ecosystem/animation.md#d3-ease) |
131
+ | `d3-interpolate` | out of the box | [animation](ecosystem/animation.md#d3-interpolate) |
132
+ | `@tweenjs/tween.js` | out of the box | [animation](ecosystem/animation.md#tweenjs) |
133
+ | `flubber` | out of the box | [animation](ecosystem/animation.md#flubber) |
134
+ | `react-transition-group` | out of the box — with `nodeRef` | [animation](ecosystem/animation.md#react-transition-group) |
135
+ | `@react-spring/core` + `/animated` | adapter, ~20 lines (`createHost`) | [animation](ecosystem/animation.md#react-spring) |
136
+
137
+ ### Headless components
138
+
139
+ | Package | Integration | |
140
+ | ----------------------- | -------------- | ------------------------------------------------ |
141
+ | `react-stately` | out of the box | [headless](ecosystem/headless.md#react-stately) |
142
+ | `@tanstack/react-table` | out of the box | [headless](ecosystem/headless.md#tanstack-table) |
143
+
144
+ ### Layout and positioning
145
+
146
+ | Package | Integration | |
147
+ | ------------------------ | ---------------------------------------------------- | ---------------------------------------------- |
148
+ | `@floating-ui/core` | adapter, ~35 lines (platform object) | [layout](ecosystem/layout.md#floating-ui) |
149
+ | `@tanstack/virtual-core` | adapter, ~40 lines — the core, not the React wrapper | [layout](ecosystem/layout.md#tanstack-virtual) |
150
+
151
+ ### Routing
152
+
153
+ | Package | Integration | |
154
+ | -------------- | -------------------------------------------- | -------------------------------------------- |
155
+ | `wouter` | out of the box — `wouter/memory-location` | [routing](ecosystem/routing.md#wouter) |
156
+ | `react-router` | out of the box — `MemoryRouter`, no `<Link>` | [routing](ecosystem/routing.md#react-router) |
157
+
158
+ ### Internationalization
159
+
160
+ | Package | Integration | |
161
+ | --------------------------- | -------------- | ------------------------- |
162
+ | `i18next` + `react-i18next` | out of the box | [i18n](ecosystem/i18n.md) |
163
+
164
+ ### Testing
165
+
166
+ | Package | Integration | |
167
+ | ---------------------- | -------------------------------------------------- | --------------------------------------------------- |
168
+ | `node:test` (built-in) | out of the box | [testing](ecosystem/testing.md#runners) |
169
+ | `vitest` | out of the box | [testing](ecosystem/testing.md#vitest) |
170
+ | `msw` | out of the box — `msw/node` | [testing](ecosystem/testing.md#msw) |
171
+ | `fast-check` | out of the box | [testing](ecosystem/testing.md#fast-check) |
172
+ | `sinon` | out of the box — one required `toFake` restriction | [testing](ecosystem/testing.md#sinon) |
173
+ | `pixelmatch` | out of the box | [testing](ecosystem/testing.md#pixelmatch) |
174
+ | `react-test-renderer` | out of the box — but deprecated upstream | [testing](ecosystem/testing.md#react-test-renderer) |
175
+
176
+ ### Developer tooling
177
+
178
+ | Package | Integration | |
179
+ | ------------------------------------------ | ---------------------------------------------------------- | ---------------------------------------------------------- |
180
+ | `react-devtools-core` | out of the box — already wired behind `REACT_X11_DEVTOOLS` | [dev tooling](ecosystem/dev-tooling.md#react-devtools) |
181
+ | `react-refresh` + `hot-module-replacement` | supported — the `react-x11/refresh` entry point | [dev tooling](ecosystem/dev-tooling.md#react-refresh) |
182
+ | `node --inspect` (built-in) | out of the box | [dev tooling](ecosystem/dev-tooling.md#node-inspect) |
183
+ | `0x` | out of the box | [dev tooling](ecosystem/dev-tooling.md#0x) |
184
+ | `@welldone-software/why-did-you-render` | out of the box | [dev tooling](ecosystem/dev-tooling.md#why-did-you-render) |
185
+
186
+ ## What does not work
187
+
188
+ Everything below was reproduced against react-x11 1.2.0, and the error text
189
+ is verbatim — if you searched for one of these strings, this is the right
190
+ page. Failures come in four flavours, by cost:
191
+
192
+ - **Install and import time** — loud, immediate, cheap.
193
+ - **Render time** — loud, immediate; the message usually names the
194
+ offending element.
195
+ - **First interaction** — the tree mounts clean and breaks on the first
196
+ keystroke, with a stack trace that points at the library, not the
197
+ renderer.
198
+ - **Silent** — no error, ever. By far the most expensive; read that table
199
+ even if nothing is broken yet.
200
+
201
+ ### Install and import time
202
+
203
+ | Package | Error | Use instead |
204
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
205
+ | `react-redux@8` | `npm error code ERESOLVE` … `peer react@"^16.8 \|\| ^17.0 \|\| ^18.0" from react-redux@8.1.3` | `react-redux@9` — [state](ecosystem/state.md#redux) |
206
+ | `react-redux@8` (past ERESOLVE) | `Error: Cannot find module 'react-dom'` from `react-redux/lib/utils/reactBatchedUpdates.js` | `react-redux@9` |
207
+ | `@tanstack/react-virtual` | `Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'react-dom' imported from node_modules/@tanstack/react-virtual/dist/esm/index.js` | `@tanstack/virtual-core` — [layout](ecosystem/layout.md#tanstack-virtual) |
208
+ | `styled-components` | `TypeError: styled.div is not a function` | `createStyles`/`ThemeProvider` + a palette package — [theming](ecosystem/theming.md) |
209
+ | `react-scan` | `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './auto' is not defined by "exports" in node_modules/react-scan/package.json imported from …` | React's own `<Profiler>`, or why-did-you-render — [dev tooling](ecosystem/dev-tooling.md#why-did-you-render) |
210
+ | `@testing-library/react` (no `react-dom`) | `Error: Cannot find module 'react-dom/test-utils'` | `react-x11/test` on `node:test` or `vitest` — [testing](testing.md) |
211
+ | `jest` (no ESM config) | `Jest encountered an unexpected token` … `SyntaxError: Cannot use import statement outside a module` | `node:test`/`vitest`, or Jest in ESM mode — [testing](ecosystem/testing.md#jest) |
212
+ | `jest` (transformed to CJS) | `SyntaxError: Cannot use 'import.meta' outside a module` | as above |
213
+
214
+ The `styled-components` error is misleading: it fires at module evaluation,
215
+ mentions neither react-x11 nor the DOM, and looks like a version mismatch.
216
+
217
+ ```js
218
+ import styled from 'styled-components';
219
+ const Panel = styled.div`
220
+ background: #1e1e2e;
221
+ `; // throws right here
222
+ ```
223
+
224
+ Under plain Node ESM (how react-x11 apps run, with no bundler) the default
225
+ import resolves to the CJS module namespace — an object with
226
+ `ServerStyleSheet` and friends, and no `.div`. Fixing the interop with
227
+ `const styled = sc.default ?? sc` only moves you to
228
+ `react-x11: unknown element type <div>`; `styled('box')` is in
229
+ [silent failures](#silent-failures).
230
+
231
+ The two Jest entries are the same dead end from two directions. Full text:
232
+
233
+ ```
234
+ Jest encountered an unexpected token
235
+ …
236
+ node_modules/react-x11/src/Reconciler.js:27
237
+ const _require = (0, _nodeModule.createRequire)(import.meta.url);
238
+ ^^^^
239
+ SyntaxError: Cannot use 'import.meta' outside a module
240
+ ```
241
+
242
+ react-x11 calls `createRequire(import.meta.url)`, which cannot be
243
+ down-compiled to CJS, so Jest runs react-x11 tests only in real ESM mode —
244
+ see [testing](ecosystem/testing.md#jest).
245
+
246
+ ### Render time
247
+
248
+ The renderer's own errors are prefixed `react-x11:` and name the element it
249
+ could not create. By far the most common failure; the tag tells you which
250
+ library layer broke.
251
+
252
+ | Package | Error | Use instead |
253
+ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
254
+ | `framer-motion` | `react-x11: uncaught error Error: react-x11: unknown element type <div>. Supported: <window>, <popup>, <box>, <text>, <image>, <canvas>, <textinput>, <textarea>, <svg>, <glarea>.` | popmotion, `@tweenjs/tween.js`, d3-ease + d3-interpolate — [animation](ecosystem/animation.md) |
255
+ | `framer-motion` (value layer) | `ReferenceError: HTMLElement is not defined` | popmotion — [animation](ecosystem/animation.md#popmotion) |
256
+ | `recharts` | `react-x11: uncaught error Error: react-x11: unknown element type <div>. …` | d3-scale + d3-shape into the `<svg>` host — [below](#charting) |
257
+ | `formik` (`<Form>` with a `<Field>`) | `react-x11: uncaught error Error: react-x11: unknown element type <input>. …` | a `<Field>` render prop onto a `<textinput>` — [forms](ecosystem/forms.md#formik) |
258
+ | `formik` (`<Form>` alone) | `react-x11: uncaught error Error: react-x11: unknown element type <form>. …` | no `<Form>`; call `submitForm()` from a `Button` |
259
+ | `@headlessui/react` (`Switch`) | `react-x11: uncaught error Error: react-x11: unknown element type <button>. …` | react-x11's built-in widgets — [components](components.md) |
260
+ | `@headlessui/react` (`Dialog`) | `react-x11: uncaught error Error: react-x11: unknown element type <span>. …` | react-x11's built-in `Dialog` |
261
+ | `@radix-ui/react-dialog` | `react-x11: uncaught error Error: react-x11: unknown element type <button>. …` | react-x11's built-in `Dialog` |
262
+ | `react-select` | `react-x11: uncaught error Error: react-x11: unknown element type <style>. …` | react-x11's built-in `Select` |
263
+ | `@emotion/styled` | `react-x11: uncaught error Error: react-x11: unknown element type <style>. …` | `createStyles` + `ThemeProvider` — [styling](styling.md) |
264
+ | `react-dropzone` | `react-x11: uncaught error Error: react-x11: unknown element type <input>. …` | built-in `useDropTarget` / `<box dropAccept onDrop>` — [drag and drop](drag-and-drop.md) |
265
+ | `react-router-dom` (`BrowserRouter`) | `react-x11: uncaught error ReferenceError: document is not defined` at `getUrlBasedHistory` | `MemoryRouter` — [routing](ecosystem/routing.md#react-router) |
266
+ | `react-router-dom` (`<Link>`) | `react-x11: uncaught error Error: react-x11: unknown element type <a>. …` | `useNavigate()` on a `<box onClick>` |
267
+ | `lucide-react` | `react-x11: uncaught error Error: react-x11: <svg width=…> is a style property — pass it in style: <svg style={{ width: … }} />` | `@iconify-json/lucide`, or `lucide` — [icons](ecosystem/icons.md) |
268
+ | `@tabler/icons-react` | `react-x11: uncaught error Error: react-x11: <svg width=…> is a style property — pass it in style: <svg style={{ width: … }} />` | `@iconify-json/tabler`, or `@tabler/icons` — [icons](ecosystem/icons.md#tabler-icons) |
269
+ | `@phosphor-icons/react` | `react-x11: uncaught error Error: react-x11: <svg width=…> is a style property — pass it in style: <svg style={{ width: … }} />` | `@iconify-json/ph`, or `@phosphor-icons/core` — [icons](ecosystem/icons.md#phosphor-icons) |
270
+ | `@testing-library/react` | `ReferenceError: document is not defined` at `render (node_modules/@testing-library/react/dist/pure.js:256:5)` | `renderX11` from `react-x11/test` — [testing](testing.md) |
271
+ | `@testing-library/dom` (`within`) | `TypeError: Expected container to be an Element, a Document or a DocumentFragment but got WindowNode.` | `within` from `react-x11/test` — [testing](testing.md) |
272
+ | `@testing-library/dom` (`screen`) | `TypeError: For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error` | `screen` from `react-x11/test` — [testing](testing.md) |
273
+ | `@testing-library/user-event` | `TypeError: Cannot read properties of undefined (reading 'Symbol(Node prepared with document state workarounds)')` | `userEvent` from `react-x11/test`, or raw ntk events — [testing](ecosystem/testing.md#driving-events) |
274
+ | `jest-image-snapshot` | `TypeError: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of Object` | `getImageData` + `pngjs` + `pixelmatch` — [testing](ecosystem/testing.md#pixelmatch) |
275
+ | `react-x11` test selectors | `Error: Test selector API is not supported by this renderer.` | nothing — `supportsTestSelectors` is `false` |
276
+
277
+ Four of those need detail, because the obvious workaround fails.
278
+
279
+ **framer-motion cannot be rescued by dropping to its value layer.** Reaching
280
+ past `motion.div` fails too:
281
+
282
+ ```js
283
+ import { animate, motionValue } from 'framer-motion';
284
+ const mv = motionValue(0);
285
+ mv.on('change', (v) => console.log(v));
286
+ animate(mv, 100, { duration: 0.1 });
287
+ // ReferenceError: HTMLElement is not defined
288
+ ```
289
+
290
+ `motion-dom` feature-detects the Web Animations API with
291
+ `subject instanceof HTMLElement`, so `animate()` on a plain `motionValue`
292
+ still throws, asynchronously, once keyframes resolve (from
293
+ `motion-dom/src/animation/waapi/supports/waapi.ts`). Use popmotion's
294
+ `animate()` instead.
295
+
296
+ **The Radix escape hatch is worse than the error.**
297
+ `<Dialog.Portal><Dialog.Content /></Dialog.Portal>` produces no error and no
298
+ output: `Portal` is SSR-guarded, finds no `document`, and renders nothing.
299
+ Every Radix primitive has that shape. (`@radix-ui/colors` is pure data and
300
+ [recommended](ecosystem/theming.md#radix-colors).)
301
+
302
+ **react-dropzone fails twice.** Deleting the `<input>` does not rescue it:
303
+ with only `<box {...getRootProps()} />` you get past the reconciler and then
304
+ hit `react-x11: uncaught error ReferenceError: window is not defined`,
305
+ thrown from react-dropzone's own mount effect.
306
+
307
+ **The three `*-react` icon packages produce a byte-identical error**, not
308
+ "unknown element type": react-x11 has a real `<svg>` host, so the icon gets
309
+ further and dies on the flat `width`/`height` props those wrappers always
310
+ set. No prop avoids it. `@heroicons/react` is the
311
+ [exception](ecosystem/icons.md#heroicons-react): it sizes with a class name,
312
+ so it renders.
313
+
314
+ Index notes for searchers:
315
+
316
+ - `react-select` reports `<style>`, not `<div>`: it is built on Emotion, and
317
+ the first host it emits is Emotion's injected style tag.
318
+ - `formik` reports `<input>` when your `<Form>` has a `<Field>` in it and
319
+ `<form>` when it does not, because the reconciler completes children
320
+ first.
321
+ - `react-router-dom`'s `<Link>` with a bare string child hits the raw-text
322
+ error first: `react-x11: raw text "go" must be wrapped in a <text> element
323
+ (or be the string child of an SVG <text>).`
324
+
325
+ #### Charting, without recharts {#charting}
326
+
327
+ The substitute for `recharts` is small: compute with `d3-scale` +
328
+ `d3-shape` and emit the path into react-x11's own `<svg>` host.
329
+
330
+ ```jsx
331
+ import { scaleLinear } from 'd3-scale';
332
+ import { line } from 'd3-shape';
333
+
334
+ const data = [
335
+ [0, 3],
336
+ [1, 7],
337
+ [2, 4],
338
+ [3, 9],
339
+ [4, 6],
340
+ ];
341
+ const x = scaleLinear().domain([0, 4]).range([0, 200]);
342
+ const y = scaleLinear().domain([0, 10]).range([100, 0]);
343
+ const d = line()
344
+ .x((p) => x(p[0]))
345
+ .y((p) => y(p[1]))(data);
346
+
347
+ <svg style={{ width: 200, height: 100 }} viewBox="0 0 200 100">
348
+ <path d={d} stroke="#89b4fa" fill="none" strokeWidth={2} />
349
+ </svg>;
350
+ ```
351
+
352
+ The `<canvas>` host with an `onDraw` handler is the other option, and the
353
+ better one for dense plots.
354
+
355
+ ### First interaction
356
+
357
+ These mount without an error; the first sign of trouble is a keystroke.
358
+
359
+ Nothing currently fails here. `downshift` (a TypeError on the first
360
+ keystroke) and `formik`'s `getFieldProps` spread (the field silently never
361
+ updated) did on 1.x, when `<textinput>` called `onChange(newString)`; it now
362
+ passes a synthetic event and both work ([forms](ecosystem/forms.md)). The
363
+ two shapes this class of bug takes:
364
+
365
+ - A handler that reads `event.nativeEvent.<something>` **unguarded** works
366
+ for a keystroke and throws for a paste or an undo, where there is no X
367
+ event to report. downshift reads
368
+ `event.nativeEvent.preventDownshiftDefault` this way, and is safe only
369
+ because it checks `hasOwnProperty('nativeEvent')` first and the property
370
+ is always present.
371
+ - A library that writes through a ref — `ref.value = ''` — needs the node to
372
+ have a value **setter**. `<textinput>` has one; most nodes do not, and the
373
+ TypeError is thrown inside the commit phase, taking the render down rather
374
+ than one handler.
375
+
376
+ ### Silent failures
377
+
378
+ No error is ever printed. Read this table before you spend an afternoon.
379
+
380
+ | Package | What happens | Fix |
381
+ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
382
+ | `swr` | `(silent) data never refetches when the X11 window regains focus — no error, no warning, revalidateOnFocus just never fires` | define `globalThis.window` before importing swr, or use `@tanstack/react-query` — [data fetching](ecosystem/data-fetching.md#swr) |
383
+ | `@tanstack/react-virtual` (with `react-dom` installed) | `(silent) with react-dom installed the import resolves and the list renders, but the flushSync re-measure applies to react-dom's reconciler, not react-x11's` | `@tanstack/virtual-core` — [layout](ecosystem/layout.md#tanstack-virtual) |
384
+ | `react-scan` | `(silent) no error, no output — onRender never fires and getReport() stays empty` | React's own `<Profiler>` (verified working), or why-did-you-render |
385
+ | `@radix-ui/react-dialog` (`Dialog.Portal`) | renders nothing; the SSR guard finds no `document` | react-x11's built-in `Dialog` |
386
+ | `styled-components` (`styled('box')`) | renders with no error and hands the box a single `className` prop, which react-x11 ignores — the CSS goes nowhere | `createStyles` + `ThemeProvider` |
387
+ | `tailwindcss/colors` (raw values) | v4 ships `oklch()` strings; ntk's parser returns null and paints nothing | convert with `culori` — [theming](ecosystem/theming.md#tailwind-colors) |
388
+
389
+ The swr one is the most expensive. `useSWR` fetches, caches and dedupes,
390
+ but swr decides once at import that a process with no global `window` is a
391
+ server and registers no focus or reconnect listeners — not even a custom
392
+ `initFocus` passed through `<SWRConfig value={{ provider, initFocus }}>`,
393
+ the documented React Native escape hatch. Details and the workaround:
394
+ [data fetching](ecosystem/data-fetching.md#swr).
395
+
396
+ `@tanstack/react-virtual` is subtle differently. `react-dom` is a _required_
397
+ peer, so a default `npm i @tanstack/react-virtual` installs it and the
398
+ import-time error never appears; `react-dom@19`'s `flushSync()` outside any
399
+ react-dom root runs the callback without throwing, so nothing warns you that
400
+ the virtualizer's synchronous flush happens in the wrong renderer.
401
+
402
+ ## Adding a library that is not listed
403
+
404
+ Run the [30-second test](#the-30-second-test) first; it settles most cases
405
+ without an install. If it passes, render it:
406
+
407
+ ```jsx
408
+ // probe.jsx — needs a display: run under $DISPLAY, or `xvfb-run -a`
409
+ import { createRoot } from 'react-x11';
410
+ import { TheThing } from 'the-package';
411
+
412
+ (await createRoot()).render(
413
+ <window width={300} height={200} title="probe">
414
+ <box style={{ flexGrow: 1 }}>
415
+ <TheThing />
416
+ </box>
417
+ </window>,
418
+ );
419
+ ```
420
+
421
+ Four outcomes:
422
+
423
+ - **`react-x11: unknown element type <…>`** — the library renders DOM hosts.
424
+ Look for a headless core published as a separate package; that is what
425
+ rescued TanStack Virtual, Floating UI and react-spring.
426
+ - **`react-x11: <… width=…> is a style property`** — it reached a real
427
+ react-x11 host and passed a flat style prop. Usually fixable by wrapping
428
+ the component rather than replacing it.
429
+ - **`ReferenceError: document is not defined`** (or `window`, or
430
+ `HTMLElement`) — a DOM global at module or mount time. Look for a
431
+ documented environment-override seam, like `@tanstack/react-query`'s
432
+ `environmentManager`.
433
+ - **It renders.** Then type into it, click it, and resize the window; the
434
+ event-shape and silent classes only show up here.
435
+
436
+ If you establish a result either way, open an issue on
437
+ [the react-x11 repository](https://github.com/sidorares/react-x11/issues)
438
+ with the package name, its exact version, the code you ran, and the verbatim
439
+ output. Negative results are as useful as positive ones.