Reactivity
Signals · watchProxy() makes plain objects reactive
Fine-grained signals with automatic dependency tracking. State stays a plain object — no wrapper to unwrap, no dependency array to keep correct.
let total = 0
$: withTax = total * 1.2 // recomputes when total changes
Replaces
React hooks + dependency arraysMobXImmer
Template
{#if} {#each} {#await} {#key} · snippets · bindings
Block directives rather than expressions, keyed lists, await blocks for promises, reusable snippets, and two-way binding that does not require an onChange handler.
{#each rows as row (row.id)}
<Row {row} />
{:else}
<EmptyState />
{/each}
Replaces
JSX + .map() + ternaries
Styles
Scoped per component
A style block applies to its own component only, with no naming convention to maintain and no runtime style injection.
Replaces
CSS Modulesstyled-componentsEmotion
Source
.mesa or Markdown with frontmatter
Content-shaped pages stay content-shaped: a Markdown file compiles to the same component, with tables and syntax highlighting already handled.
Targets
DOM · SSR · static · email · fragment · modules
The same component renders live in the browser, to an HTML string on the server, to a prerendered file, to an email, or to an isolated fragment for embedding.
Replaces
separate SSR and email renderers
Attachments
{@attach} — an element handed to your code
The escape hatch for a chart library or a focus trap: you get the node and a teardown. It does not run on the server, which is what makes a server-rendered page safe to write this way.
Replaces
useEffect + a refdirectiveslifecycle hooks
Leaf
No framework dependency of its own
Mesa sits at the bottom, so it can be adopted with any bundler and any server. The rest of the framework is what happens when you keep going.
Replaces
Nothing — there is no common equivalent to swap out.