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