Ahead of the release
npm install @evanion/react-widget gives you 0.3.0. These pages document main, which has changes that release does not.
Playground
A page the shop would ship
The counter’s view of Baize below is one Widgets region: a figures row and
two boards, composed from the seven items printed under it. Every block is a
component somebody wrote once, and the items decide which blocks the page has,
what sits inside what and how wide each one is.
Move an item with the controls in the gutter and the page is composed again.
Moving counter above week carries two boards and three figures as one
block, which a nested item list expresses and a flat items.map cannot; moving tables past reprints swaps the wide side, because
meta.span belongs to the item and travels with it.
Tonight at the tables
| Table | Game | Party | State |
|---|---|---|---|
| One | Brass: Birmingham | Hanna Lind, +3 | Playing |
| Two | Spirit Island | Otto Ruane, +2 | Playing |
| Three | Root | Sigrid Vall, +3 | Teaching |
| Four | Crokinole | Emil Norrby, +1 | Booked, 20:00 |
Reprints on order
| Title | Due |
|---|---|
| Wingspan, Oceania | Tuesday |
| Hive Pocket | Thursday |
| Azul, Summer Pavilion | Next week |
itemsMove one and the page is composed again
[ { "id": "week", "type": "columns", "props": {}, "children": [ { "id": "intake", "type": "metric", "props": { "figure": "38", "label": "Games in", "delta": "+6" } }, { "id": "sold", "type": "metric", "props": { "figure": "31", "label": "Sold", "delta": "+2" } }, { "id": "turnaround", "type": "metric", "props": { "figure": "2.4 d", "label": "Turnaround", "delta": "−0.3" } } ] }, { "id": "counter", "type": "columns", "props": {}, "children": [ { "id": "tables", "type": "tables", "props": { "title": "Tonight at the tables" }, "meta": { "span": 2 } }, { "id": "reprints", "type": "reprints", "props": { "title": "Reprints on order" } } ] }]The same demonstration opens the front page. What is on screen is the published renderer over the items printed beside it — nothing here is a picture of a page.
Your own items
The editors below run the published @evanion/react-widget build.
Try these examples
What a snippet can use
Each snippet is evaluated by react-live in noInline mode against a fixed
scope. There is no module resolution inside one, so an import line, or a name
that is not in the scope, surfaces as a runtime error in the preview pane rather
than as a build failure.
Available: createWidgets, React, useState, useEffect, useMemo,
useCallback, and render — which every snippet has to end in.
const { Widgets } = createWidgets({ components: { text: Text } });
render(<Widgets items={[{ id: 't', type: 'text', props: { body: 'hi' } }]} />);Things that behave differently here
Everything runs in the browser. The package is importable from a React Server
Component, but nothing in a playground is one, so async widgets and the
streaming behaviour described under Suspense cannot
be demonstrated here — chrome.suspenseFallback still works, but only for a
widget that suspends on the client.
Type errors do not show. The snippets are strings; nothing typechecks them, so
an unknown type,
mismatched props and children on a component that does not take them all run
here without complaint. What the editor does show is the rendered output, the
chrome composing around it, and the console warning when an item names a type
the map does not have.
Try changing
- A
typeto something not in thecomponentsmap. The item disappears and the browser console carries one warning naming itsid. - A
propskey. Nothing validates it at runtime — the widget just receivesundefined— which is the gap the type checker closes outside this editor. - The
chrome.wrapper, to see how the region container composes. - An item’s position in the array.
idis the React key, so reordering moves the element rather than rebuilding it.