splay

Render any data. Register one viewer for each type. dispatch finds the type of each value, calls its viewer, and the viewer calls ctx.render for the values inside. The output is yours: elements, strings or component data.

Playground

1 Data

JSON has no dates and no symbols. The page reads {"$date": "2026-11-03"} as a Date, and a key "$type" as the TYPE_SYMBOL of its object.

2 Viewer set
Viewers in the registry Select one to turn it off. The number is the count of values of that type.

The layout helpers, live

A viewer gets a size, and gives sizes to its children. Three helpers calculate the boxes. Drag the corner of the container, or move the sliders.

How dispatch works

The core is about 200 lines of TypeScript with no dependencies. Each call of dispatch does these four steps.

  1. 1

    Find the type

    inferType(data) gives "null", "undefined", "function" or the typeof of a primitive. For an object, the value of its TYPE_SYMBOL comes first, then "array", "date" and "object".

  2. 2

    Find the viewer

    registry.get(type) gives the viewer of that type. A registry is a map from a type to a viewer.

  3. 3

    No viewer? Use the fallback

    With no viewer, dispatch gives fallback(type, data), or undefined when the config has no fallback. Turn off a viewer above to see it.

  4. 4

    Call the viewer

    The viewer gets ctx: data, size, path, depth and render. ctx.render(child, size, path) starts step 1 again for each nested value.

API

The page runs each example with the package, and shows the result. size and box are { width: 300, height: 100 }.

Install

@mark1russell7/splay v 0 dependencies MIT npm GitHub Releases

Add the package

pnpm add @mark1russell7/splay

Use it

Splay is part of client: its procedure results render with splay.

text-viewers.ts: the plain string viewers of this page