SolidJS logoSolidJS INTERMEDIATE

SolidJS

A comprehensive cheat sheet for SolidJS, the reactive JavaScript framework with fine-grained reactivity, signals, stores, and control flow components.

8 min read
solidjssolidreactivesignalsjavascriptfrontendframeworkui

Components & JSX

SolidJS components are plain functions that run once. JSX compiles to real DOM operations, not a virtual DOM.

Component Basics

Components are functions that return JSX. They execute only once — reactivity handles updates.

tsx
💡 Components run only ONCE — unlike React, the function body is not re-executed on updates
⚡ Use class instead of className for HTML attributes in SolidJS JSX
📌 Do NOT destructure props — it breaks reactivity since props are lazy getters
🟢 SolidJS compiles JSX to real DOM operations, not a virtual DOM
componentsjsxbasics

Event Handling

Handle DOM events with on-prefixed attributes and native event delegation.

tsx
💡 SolidJS uses event delegation for common events — they're handled at the document level
⚡ Use on: prefix (e.g., on:scroll) for events that should NOT be delegated
📌 Pass a tuple [handler, data] to bind data to an event without creating a closure
🟢 Events use native DOM types — e.currentTarget is properly typed in TypeScript
eventsdelegationhandlers

Signals

Signals are the core reactive primitive in SolidJS. They hold values and automatically track dependencies.

createSignal

Create a reactive signal that returns a getter function and a setter function.

typescript
💡 Signals return getter functions — always call them with () to read the value
⚡ Setter accepts a direct value or a callback receiving the previous value
📌 Pass { equals: false } to always notify subscribers even if value is unchanged
🟢 Signals are the foundation of all reactivity in SolidJS
signalsstatereactivity

Derived Signals

Create computed values by wrapping signal reads in a function — no special API needed.

typescript
💡 Derived signals are plain functions — no API needed, just read signals inside a function
⚡ They re-evaluate on every access, which is fine for cheap computations
📌 For expensive computations, use createMemo instead for caching
🟢 This pattern is unique to SolidJS — no useMemo or computed() wrappers needed
signalsderivedcomputed

Control Flow

SolidJS uses components for control flow instead of JavaScript expressions to maintain fine-grained reactivity.

Show & For

Conditionally render with Show and efficiently iterate lists with For.

tsx
💡 Show renders children when the "when" prop is truthy, fallback otherwise
⚡ For is keyed by reference — each item maintains its own DOM nodes across updates
📌 In For, the item is a plain value but the index is a signal — call index() to read it
🟢 Use For for arrays of objects, Index for arrays of primitives
showforconditionallist

Switch, Match & Index

Multi-condition rendering with Switch/Match and primitive-keyed iteration with Index.

tsx
💡 Switch renders the first matching Match — use fallback for the default case
⚡ Index is keyed by position — use it for primitive arrays (strings, numbers)
📌 In Index, the item is a signal but the index is a plain number — opposite of For
🟢 For vs Index: For recycles DOM nodes by reference, Index recycles by position
switchmatchindexcontrol-flow

Effects & Memos

Effects run side effects in response to signal changes. Memos cache derived values for performance.

createEffect

Run a side effect that automatically re-executes when its signal dependencies change.

typescript
💡 Effects auto-track dependencies — any signal called inside is a dependency
⚡ Effects run synchronously after render and re-run when dependencies change
📌 Return a value from the effect callback to access it as the previous value on next run
🟢 Use createEffect for side effects like logging, DOM manipulation, or external API calls
effectsreactivityside-effects

createMemo

Create a cached derived value that only recomputes when its dependencies change.

typescript
💡 createMemo caches its result — unlike derived signals, it only recomputes when dependencies change
⚡ Memos are themselves signals and can be tracked by effects and other memos
📌 Use memos for expensive computations or values read in multiple places
🟢 Think of createMemo as a derived signal with built-in caching
memocomputedcaching

Props Utilities

SolidJS props are reactive getters. Use mergeProps, splitProps, and children() to work with them safely.

mergeProps & splitProps

Set default props with mergeProps and separate local from pass-through props with splitProps.

tsx
💡 Never destructure props — it reads the value once and loses reactivity
⚡ splitProps returns [picked, rest] — perfect for passing remaining props to DOM elements
📌 mergeProps creates a new reactive object with defaults that can be overridden
🟢 These utilities exist because destructuring breaks the reactive proxy
propsmergePropssplitProps

children Helper

Resolve and manipulate children reactively with the children() utility.

tsx
💡 Use children() to resolve lazy children into a memoized reactive value
⚡ Call resolved.toArray() to get an array of child elements for inspection
📌 ParentProps<T> is a convenience type that adds children to your props interface
🟢 Only use children() when you need to inspect or transform children — otherwise just use props.children
childrenpropscomposition

Lifecycle

SolidJS lifecycle hooks for setup and cleanup within components.

onMount & onCleanup

Run code after the component mounts or when it unmounts.

typescript
💡 onMount runs once after the component is first rendered to the DOM
⚡ onCleanup works in both components and effects — cleans up between re-runs too
📌 Since components run only once, you can set up intervals directly in the function body
🟢 onMount is equivalent to createEffect that runs only on first execution
lifecyclemountcleanup

Context

Share reactive state across the component tree without prop drilling.

createContext & useContext

Create and consume context to share state across deeply nested components.

tsx
💡 Context values can include signals and setters for reactive shared state
⚡ Create a custom useX hook that throws if context is missing for better DX
📌 Context is great for themes, auth, i18n, and other app-wide state
🟢 Unlike React, context consumers don't re-render — only the signal reads update
contextstate-sharingprovider

Stores

Stores provide reactive state for nested objects and arrays with fine-grained updates.

createStore

Create a reactive store for complex nested state with path-based updates.

typescript
💡 Store properties are accessed directly (state.count) — no getter function call needed
⚡ Path-based setState only triggers updates for the exact changed property
📌 Use a function as a path segment to match array items by condition
🟢 Stores are ideal for complex state — signals are better for simple atomic values
storesstatenested

produce & reconcile

Use produce for mutable-style updates and reconcile for replacing store data.

typescript
💡 produce lets you write mutable-looking code that produces immutable updates
⚡ reconcile diffs new data against the store to make minimal reactive updates
📌 Use reconcile when replacing store data from API responses for best performance
🟢 produce is imported from "solid-js/store", not from a separate package
storesproducereconcile

Refs & DOM Access

Access and manipulate DOM elements directly using refs and directives.

Refs & Forwarding

Get direct access to DOM elements using ref and forward refs to parent components.

tsx
💡 Use the ! (definite assignment) operator since refs are assigned after render
⚡ Callback refs run immediately when the element is created — useful for canvas setup
📌 Access refs in onMount, not in the component body — the element may not exist yet
🟢 Forward refs by passing them as regular props — no special forwardRef API needed
refsdomelements

Resources & Data Fetching

createResource provides a reactive way to handle async data with built-in loading and error states.

createResource

Fetch async data reactively with automatic loading/error tracking and optional source signals.

tsx
💡 Pass a source signal as the first arg to auto-refetch when it changes
⚡ mutate() updates the local data optimistically without refetching
📌 refetch() manually triggers a new fetch — great for refresh buttons or polling
🟢 Combine with Suspense and ErrorBoundary for declarative loading states
resourceasyncfetching

Portals & Error Boundaries

Render content outside the component tree and handle errors declaratively.

Portal & ErrorBoundary

Render components into a different DOM node and catch errors in the component tree.

tsx
💡 Portal renders children into a target DOM element outside the component hierarchy
⚡ ErrorBoundary fallback receives the error and a reset function to retry rendering
📌 Combine ErrorBoundary with Suspense for complete async error and loading handling
🟢 Portal defaults to document.body — pass mount prop to target a specific element
portalerror-boundarysuspense

Reactivity Utilities

Advanced reactivity helpers for batching updates, untracking reads, and observing signals.

batch, untrack & on

Control reactivity with batching, untracking, and explicit dependency declarations.

typescript
💡 batch prevents intermediate updates — effects and memos update once after all changes
⚡ untrack reads the current signal value without creating a dependency
📌 on() explicitly declares dependencies — useful when you want to ignore some signals
🟢 Pass { defer: true } to on() to skip the initial execution of the effect
batchuntrackonreactivity