Solid.js, which self-describes as a reactive JavaScript UI library, recently released its first major iteration. Solid replicates many capabilities (e.g., server-side rendering, concurrent rendering) and APIs (e.g., stores, context, directives) available in other UI frameworks. Developers describe how the appearance and behavior of user interfaces relate to a set of reactive dependencies. Solid compiles the statements to imperative DOM operations.
Web applications are reactive applications whose behavior is the specification of how the application reacts to incoming events. That reaction typically consists of updating the state of the application and executing commands that affect the systems the application interfaces with. Solid lets developers reify the state of the application as reactive values and bind events to state updates and command execution.
A simple application that iterates through a list of colors every second
may be defined in pseudo-code by the following declarative statements:
colors ≡ ["blue", "red", "green"]
index ≡ count mod 3
color ≡ colors[index]
init => count <- 0, set recurring timer
exit => cancel timer
second elapsed => count <- count + 1
color update => render <div style={{color: color()}}>Color: {color()}</div>;
The previous pseudo-code showcases reactions (event => reactions
), which may update variables (signals) and execute commands (effects), and equations (x ≡ y
). Equations are implemented with Solid’s derived signals, which ensure that anytime the right hand changes, the left hand is updated to maintain the equality.
The previous pseudo-code translates to Solid’s APIs as follows:
import { render } from "solid-js/web";
import { createSignal, onCleanup, onMount } from "solid-js";
function Counter() {
// `colors` is a constant so no need to use a signal
const colors = ["blue", "red", "green"];
// `count` signal
const [count, setCount] = createSignal();
let timer;
// Derived signals
const index = () => count() % 3;
const color = () => colors[index()];
// init event handler
onMount(() => {
setCount(0);
timer = setInterval(() => setCount(count() + 1), 1000);
});
// exit event handler
onCleanup(() => clearInterval(timer));
// Baked-in render command handler
// will automatically detect the reactive dependencies (`color`)
// that trigger the render command
return <div style={{color: color()}}>Color: {color()}</div>;
}
// Starting the application
render(() => <Counter />, document.getElementById('app'));
Solid’s compiler then compiles the previous code to optimize the rendering process:
import { template, render, createComponent, insert, effect } from 'solid-js/web';
import { createSignal, onMount, onCleanup } from 'solid-js';
const _tmpl$ = template(`<div>Color: </div>`, 2);
function Counter() {
const colors = ["blue", "red", "green"];
const [count, setCount] = createSignal();
let timer;
const index = () => count() % 3;
const color = () => colors[index()];
onMount(() => {
setCount(0);
timer = setInterval(() => setCount(count() + 1), 1000);
});
onCleanup(() => clearInterval(timer));
return (() => {
const _el$ = _tmpl$.cloneNode(true);
_el$.firstChild;
insert(_el$, color, null);
effect(() => _el$.style.setProperty("color", color()));
return _el$;
})();
}
render(() => createComponent(Counter, {}), document.getElementById('app'));
The previous code showcases the creation of a DOM template (template('<div>Color: </div>', 2)
) that will be cloned (cloneNode
) and updated in place only where necessary (e.g., _el$.style.setProperty("color", color())
). Solid.js thus avoids using a virtual DOM and the associated overhead (virtual DOM computation, virtual DOM diffing). Instead, the compiled code provides both optimized creation and updates of actual DOM nodes.
The direct DOM updates may have the additional advantage of removing an abstraction layer that only imperfectly replicates the DOM (e.g., React’s SyntheticEvent
vs. native DOM events, React’s partial support of web components) and has been the source of accidental complexity and bugs.
Solid boasts advanced features that made their way to recent releases of popular UI frameworks (<Suspense>, <SuspenseList>, useTransition). Solid 1.0 ships with a dedicated site that includes plenty of documentation, tutorials, and a code playground. Solid.js is open-source software distributed under the MIT license.