Skip to content

SolidJS

Getting started with SolidJS is straightforward, especially if you’re already familiar with React. SolidJS is a powerful, fine-grained reactive framework that offers excellent performance and a familiar JSX syntax.

Below are a few videos recommended in the SolidJS documentation that can help you get started:

Play Play

For a more in-depth understanding, you can also check out the official SolidJS documentation.

This guide is designed to bridge the gap between the React and Solid. We’ll show you what’s familiar and, more importantly, explain the fundamental shift in thinking that will help you write clean, incredibly performant Solid applications.

Think of it this way: the “what” (your UI) is familiar, but the “how” (the update mechanism) is different and, once you grasp it, much simpler.


The fundamentals of creating components with JSX and passing props are nearly identical. Solid provides first-class TypeScript support to make this process robust.

  • Components are Typed Functions: You build your UI from functions that return JSX. The idiomatic way to type them is with the Component type from solid-js.
  • Props are Typed: You can define props for your components just as you would in React, typically using an interface or type alias.
TypeScript
import type { Component } from 'solid-js';
// Define the shape of your props
type GreetingProps = {
name: string;
};
// Use the Component<T> type for your component
const Greeting: Component<GreetingProps> = (props) => {
return <div>Hello, {props.name}!</div>;
};
const App: Component = () => {
return <Greeting name="Solid Developer" />;
};

The Big Difference: True Reactivity vs. the Virtual DOM

Section titled “The Big Difference: True Reactivity vs. the Virtual DOM”

This is the most important concept to understand, and it’s what makes Solid so fast.

In React, when state changes, the component function re-runs, and a Virtual DOM is used to figure out what changed.

In Solid, your component functions run only once to set up the view. They don’t re-run. Instead, Solid uses a reactive system that surgically updates the exact parts of the DOM that need to change.

React (VDOM)Solid (Reactivity)
State change triggers a component re-render.Component function runs once.
A new VDOM is created and diffed.A reactive signal directly updates the DOM.
Relies on dependency arrays (useEffect).Dependencies are tracked automatically.
”Re-run everything to figure it out.""Update only what’s necessary.”

This fundamental difference eliminates the need for dependency arrays and a whole class of bugs related to stale closures.

Here’s a practical, type-safe look at how common React hooks map to Solid’s reactive primitives.

In Solid, you use createSignal. It’s generic, so it can infer the type from its initial value, or you can provide it explicitly. A signal is a tuple containing an Accessor (the getter) and a Setter.

TypeScript
import { createSignal } from 'solid-js';
import type { Accessor, Setter } from 'solid-js';
// Type is inferred as 'number'
const [count, setCount] = createSignal(0);
// count is type: Accessor<number>
// setCount is type: Setter<number>
// You can also be explicit, which is useful for complex types
const [user, setUser] = createSignal<User | null>(null);

The most critical difference for React developers is that the state variable (count) is an accessor function, not a static value.

TypeScript
// To read the value, you must call the function:
<h1>The count is: {count()}</h1>
// This is wrong and will not be reactive:
<h1>The count is: {count}</h1>

Why? Calling count() is how you tell Solid’s reactive system that this part of your UI depends on the signal. It’s how the magic happens without a VDOM.

createEffect automatically tracks any signals you read inside it. No dependency array needed!

TypeScript
import { createEffect, createSignal } from 'solid-js';
const [count, setCount] = createSignal(0);
// This effect automatically re-runs whenever 'count()' changes
createEffect(() => {
console.log('The count is now', count());
});

For deriving reactive values, use createMemo. It also tracks its own dependencies and returns a read-only Accessor.

TypeScript
import { createMemo, createSignal } from 'solid-js';
import type { Accessor } from 'solid-js';
const [count, setCount] = createSignal(5);
// The type of doubleCount is Accessor<number>
const doubleCount: Accessor<number> = createMemo(() => count() * 2);
// Use it in your JSX just like a signal
<p>Double the count is: {doubleCount()}</p>

Because your components only run once, you cannot use array methods like .map() directly in your JSX for reactive data. To handle this, Solid provides special, typed helper components.

  • For lists, use the <For> component.
  • For conditional rendering, use the <Show> component.

These components are reactive and ensure the DOM is updated efficiently.

TypeScript
import { createSignal, For, Show } from 'solid-js';
import type { Component } from 'solid-js';
interface User {
id: number;
name: string;
}
const [users, setUsers] = createSignal<User[]>([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]);
const [currentUser, setCurrentUser] = createSignal<User>(users()[0]);
// Correct way to render a list
// 'user' is correctly typed as 'User' inside the loop
<For each={users()}>
{(user, i) => <div>{i() + 1}: {user.name}</div>}
</For>
// Correct way to show/hide content
// The 'when' prop narrows the type of 'user()' inside the block
<Show when={currentUser()} fallback={<p>No user selected.</p>}>
{user => <p>Current user is: {user.name}</p>}
</Show>