Starter page - interactive diagrams

 from Red Blob Games
14 Apr 2020

I have an interactive tutorial that takes you step by step to make an interactive tutorial in d3.js and another one in vue.js. However, the code for those is more involved than I’d like, so I wanted to make something even simpler. I wrote the same example with several libraries and made some notes for myself. I often use these as a starting point when I’m working on a project.

None of these examples go very far, such as using components or multiple modules. I’m primarily evaluating these for my interactive diagrams and not for making “web apps”.

 1  Vanilla JavaScript#

No libraries, no build step.

Demo and code[1]

Notes:

A simpler alternative to createElement etc. is to construct a string and set innerHTML. This is nice unless you have event listeners on those elements. Setting innerHTML creates new elements. If you are dragging the mouse based on an event handler, and the mouse drag replaces the elements, that mouse drag might be running on an element that no longer exists, and that can be tricky to debug. You’ll also have to be careful to escape your HTML correctly if you are setting innerHTML.

 2  Vue#

Medium sized input&output library (80k), no build step required, but Vue-specific compiler optional, and Vue-agnostic JSX also allowed but not widely used.

Notes:

Tricky:

I am avoiding framework-specific build steps because it doesn’t match my long term goals, so I am not planning to use Vue’s Single-File Components (SFC) format, including <script setup>. I use Vue without that format.

 3  Lit#

Lit: small output library (11–16k), no build step required.

Notes:

Tricky:

 4  React#

Medium sized input&output library (140k), React-agnostic build step strongly recommended to convert JSX code into regular JavaScript.

Notes:

Tricky:

 5  Preact#

Small input&output library (13k), build step if using JSX, no build step needed using HTM (+2k).

Notes:

Preact is like React, but without the tricky items I listed under React: it allows html names like class=… rather than JavaScript names like className=…; and it allows svg names like fill-opacity=… rather than fillOpacity like React requires. This means you can use an SVG visual editor and export it directly into Preact. It more closely follows standard HTML, so you can both onInput and onChange events.

It normally uses JSX like React does but Preact’s HTM is like lit-html’s format, without the tricky items I listed under lit-html: you don’t have to have both html`` and svg``; the templates support xml syntax; and there’s a prebundled version of the library.

Tricky:

 6  Svelte#

Medium sized input&output library, build step required to convert Svelte code into regular JavaScript

I did not include a demo here, because it requires its own Svelte-specific compiler, and the Svelte playground didn’t let me share a link. However I mention Svelte here because I’ve heard good things about it, and it’s worth considering.

Notes:

Tricky:

I am avoiding framework-specific build steps because it doesn’t match my long term goals, so I am not planning to use Svelte.

 7  ObservableHQ#

Notebook style interface, where top level definitions become reactive in other expressions. Think spreadsheets.

Demo[20] partially implemented ; see source by clicking to the left of any cell.

Tricky:

 8  My thoughts#

The main idea with templates is that instead of writing commands to generate html, we describe the html we want, with some placeholders for values that come from JavaScript values. For example:

<rect fill=red x=${col} y=${row} width=1 height=1 />

Compare this to the vanilla approach:

let rect = document.createElementNS("http://www.w3.org/2000/svg", 'rect');
rect.setAttribute("fill", "red");
rect.setAttribute("x", col);
rect.setAttribute("y", row);
rect.setAttribute("width", 1);
rect.setAttribute("height", 1);
svg.appendChild(rect);

or the d3.js approach:

let rect = svg.append("rect")
              .attr("fill", "red")
              .attr("x", col)
              .attr("y", row)
              .attr("width", 1)
              .attr("height", 1);

I find templates to be a big win. The major libraries in this space (React, Vue, Svelte, Preact, lit-html) all use templates, but the details differ.

<!-- react/preact/vue with jsx -->
<rect fill=red x={col} y={row} width=1 height=1 />
<!-- vue templates -->
<rect fill=red :x="col" :y="row" width=1 height=1 />
<!-- lit-html, and react/preact with htm -->
<rect fill=red x=${col} y=${row} width=1 height=1 />

There’s some difference in how the templates are written. React uses an extension of JavaScript called JSX to allow you to write html in your JavaScript. You run a React-agnostic compiler to translate that into regular JavaScript. Vue reads HTML from your document, or in strings in the source code, or you can use a Vue-specific compiler to compile Vue “SFC” syntax. Lit-html uses a relatively new feature, JavaScript template literals. Preact normally uses JSX but there’s an option to use HTM template literals. Svelte uses a Svelte-specific compiler to compile code into regular JavaScript.

In addition, React, Preact, Vue, and Svelte offer a component system that allows you to create custom elements like <GridWorld> that are then expanded into HTML. Lit-html doesn’t do this, and instead leaves that to a separate library, LitElement. For my small projects, the component system doesn’t help me, as I can use regular JavaScript functions and classes instead. However, for larger projects, it provides some modularity and also allows you to reuse components that others have written. LitElement uses standard web components that can be used with any other system, whereas React, Preact, Vue, Svelte components can only be used within their own system.

https://component-party.dev/[21] shows a comparison of the syntax used across Svelte, React, Vue, and others.

For my own projects, I want to be able to use libraries without a build step and/or without node.js. Although React can be used without a build step, it’s designed to be used with one, and the docs not only say you need to use node.js and a build step, they also recommend you adopt a bigger framework. Svelte also requires a build step. Vue, Preact, and Lit prominently mention being able to run without a build step in their “getting started” docs. I use Vue most often in my projects, and have a tutorial showing how I use it for interactive diagrams.

Email me , or tweet @redblobgames, or comment: