JSX in Solid
Why Solid's JSX looks like React's but compiles to something completely different under the hood.
អាន 2 នាទី
Solid's JSX syntax is deliberately close to React's — same curly-brace expressions, same className-becomes-class idea (Solid actually just uses class directly), same nesting rules. That similarity is intentional, so React developers feel at home. But it's worth being precise about what the compiler does with it, because the differences explain a lot of Solid's behavior later on.
React's JSX compiles to function calls
React JSX compiles roughly to nested React.createElement() calls (or jsx() calls with the newer transform), which return plain JavaScript objects describing the tree. React then walks that object tree, builds real DOM from it, and — on every re-render — builds a new object tree and diffs it against the old one.
Solid's JSX compiles to DOM instructions
Solid's compiler instead turns JSX into code that creates real DOM nodes directly and inserts small reactive bindings wherever something can change:
function Greeting() {
const [name, setName] = createSignal("World");
return <h1>Hello, {name()}!</h1>;
}This roughly compiles to something like "create an <h1> element, create a text node, insert both, and register that the text node's content should update whenever name() changes" — no virtual tree, no diffing step, ever. The {name()} expression isn't just interpolated once; the compiler recognizes it as a function call and wraps the DOM update in a reactive binding.
Expressions must stay reactive
This has a direct consequence: anything dynamic in Solid JSX should be a function call or a JSX expression the compiler can see, not a pre-computed value.
// Works: the compiler sees name() as a live expression
<h1>Hello, {name()}!</h1>
// Breaks reactivity: computed once, outside the JSX, never updates
const greeting = `Hello, ${name()}!`;
<h1>{greeting}</h1>In the second example, name() is called once when the component function runs (and remember — that's only once, ever), so greeting is just a frozen string. The <h1> has nothing reactive to bind to. This is the same underlying idea you'll see again with props: reactivity in Solid flows through function calls, and anything that unwraps a signal too early breaks the chain.
Attributes, boolean props, and events
<input
type="text"
value={name()}
disabled={isLoading()}
onInput={(e) => setName(e.target.value)}
/>Event handlers (onInput, onClick, etc.) are attached as native DOM event listeners — Solid doesn't use a synthetic event system the way React does, so e is a real Event object. Attributes like value and disabled are bound the same reactive way as text content: as functions the compiler tracks, updated directly when their signal changes.
The takeaway for this lesson: Solid's JSX is familiar to write but fundamentally different to run. Keep dynamic values as function calls inside JSX, and let the compiler do the reactive wiring — don't pre-compute them into plain variables first.