SolidJS Guide — Reactive UI Framework for High-Performance Apps
SolidJS is a reactive JavaScript UI library that delivers blazing-fast performance by compiling templates into real DOM nodes and updating only what changes — no virtual DOM, no diffing, just direct, fine-grained reactivity.
What You’ll Learn
- How SolidJS signals, effects, and memos create fine-grained reactivity
- Writing JSX that compiles to real DOM manipulations without a virtual DOM
- Using Solid’s control flow components instead of JavaScript array methods
- Managing global state with Context and createContext
- Fetching data with createResource for async operations
Why SolidJS Matters
React introduced us to declarative UI but pays a performance tax — every state change triggers a virtual DOM diff that reconciles the entire component tree. SolidJS eliminates this overhead: components render once, and only the specific DOM nodes bound to changing signals update. This means a list of 10,000 items re-renders in microseconds when one item changes, not milliseconds. Doda Browser’s tab management UI uses SolidJS because real-time tab updates need sub-millisecond reactivity to feel instant.
flowchart LR
A[JavaScript & React Concepts] --> B[SolidJS]
B --> C[Signals & Effects]
B --> D[JSX without VDOM]
B --> E[Control Flow]
B --> F[Context & Resources]
C --> G[Fine-Grained Updates]
D --> H[Direct DOM Manipulation]
style B fill:#2c4f7c,color:#fff
Core Concepts
Signals — The Atomic Unit of Reactivity
Signals are the foundation of SolidJS reactivity — they hold values and notify dependents when values change:
import { createSignal } from "solid-js";
function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count()}
</button>
);
}Output: When the button is clicked, only the text inside the button updates — not the entire component. Solid tracks exactly which DOM nodes depend on count() and updates only those nodes. There’s no virtual DOM diffing involved.
Effects — Reacting to Changes
Effects run automatically when their dependent signals change:
import { createSignal, createEffect } from "solid-js";
const [name, setName] = createSignal("Alice");
createEffect(() => {
console.log(`Name changed to: ${name()}`);
// Logs "Name changed to: Alice" immediately
// Logs again every time name() changes
});
setName("Bob"); // Logs "Name changed to: Bob"
Output: The effect runs once at initialization, then re-runs whenever name() changes. Solid automatically tracks which signals the effect reads and subscribes to them.
Memos — Derived State
Memos are cached computed values that only re-evaluate when dependencies change:
import { createSignal, createMemo } from "solid-js";
const [items, setItems] = createSignal([1, 2, 3, 4, 5]);
const total = createMemo(() => items().reduce((a, b) => a + b, 0));
// total() is cached — no recalculation until items() changes
console.log(total()); // 15
Output: total() returns 15 immediately. Adding an item to the array and calling total() again re-evaluates the memo. Accessing total() between changes returns the cached value instantly.
JSX Without Virtual DOM
SolidJS compiles your JSX into real DOM operations. The template runs once:
function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}Behind the scenes: Solid compiles this into code that creates a real <h1> element and sets up a direct binding between props.name and the text node. When props.name changes, Solid updates that single text node — no virtual DOM, no component re-render.
Control Flow Components
Solid provides built-in components that replace JavaScript array methods for better reactivity:
import { For, Show, Switch, Match } from "solid-js";
function UserList({ users, loading, status }) {
return (
<div>
<Show when={!loading} fallback={<p>Loading...</p>}>
<For each={users()}>
{(user, index) => (
<div>
{index() + 1}. {user.name}
</div>
)}
</For>
</Show>
<Switch fallback={<p>Unknown status</p>}>
<Match when={status() === "active"}>
<p>System is active</p>
</Match>
<Match when={status() === "paused"}>
<p>System is paused</p>
</Match>
</Switch>
</div>
);
}Output: <For> efficiently adds/removes/reorders DOM nodes when the array changes. <Show> conditionally renders content. <Switch>/<Match> handles multiple conditions. Unlike JavaScript’s .map(), these components track individual array items by identity, not index.
Context and Resources
import { createContext, useContext, createResource } from "solid-js";
// Context for global state
const ThemeContext = createContext("light");
function useTheme() { return useContext(ThemeContext); }
// Resource for async data
async function fetchUser(id) {
const res = await fetch(`https://api.example.com/users/${id}`);
return res.json();
}
function UserProfile(props) {
const [user] = createResource(() => props.id, fetchUser);
const theme = useTheme();
return (
<div class={`theme-${theme}`}>
<Show when={!user.loading} fallback={<p>Loading...</p>}>
<h1>{user().name}</h1>
</Show>
</div>
);
}Output: createResource wraps async data fetching with reactive loading states. When props.id changes, the resource automatically re-fetches. Context provides global theme access without prop drilling.
Common Mistakes
Calling signals without parentheses: A signal like
countreturns a getter function. Always callcount()to read the value, notcount(which returns the getter itself).Destructuring signals:
const { count, setCount } = createSignal(0)breaks reactivity. Destructuring the getter disconnects it from the reactive system. Useconst [count, setCount] = createSignal(0).Using JavaScript
.map()in JSX: Solid’s<For>component tracks items by identity. JavaScript.map()recreates DOM nodes on every change, losing state. Use<For>for lists.Creating signals inside JSX: Signals should be created at the top level of a component or module, not inside conditionals or loops. Each
createSignalcall creates a unique reactive primitive.Expecting React lifecycle behavior: SolidJS doesn’t have
useEffectdependencies arrays oruseCallback. Effects automatically track dependencies. Unnecessary wrapping causes subtle bugs.
Practice Questions
What makes SolidJS different from React? Answer: SolidJS uses no virtual DOM. It compiles JSX into real DOM operations and updates only the specific nodes bound to changing signals. React diffs the entire virtual DOM tree on every state change.
How does
createMemodiffer fromcreateEffect? Answer:createMemoproduces a cached value that other reactive primitives can read.createEffectproduces side effects (console.log, DOM mutations) that don’t return values.Why does SolidJS use
<For>instead of.map()? Answer:<For>tracks array items by identity and only updates changed items..map()recreates all DOM nodes on every render, losing internal state and causing unnecessary updates.What happens when you destructure a signal? Answer: You get the value at that moment, not a reactive getter. Changes to the original signal won’t trigger updates in your component.
Challenge
Build a real-time dashboard with SolidJS: create signals for metrics data, use createResource to fetch from a mock API every 5 seconds, display data with <For> in a table, add sorting with createMemo, and apply context for theme switching.
FAQ
Try It Yourself
# Create a new SolidJS project
npm init solid@latest my-solid-app
cd my-solid-app
npm install
npm run devReplace the default component with a counter using createSignal, add an effect that logs the count to console, wrap it in a <Show> that hides the counter when count exceeds 10, and add a second counter with createMemo for derived state.
What’s Next
| Topic | Description |
|---|---|
| Compare SolidJS with the industry standard | |
| Add types to your SolidJS project |
Related topics: JavaScript, TypeScript, React, Node.js
What’s Next
Congratulations on completing this SolidJS tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro