FrontierJS

Mesa

UI · Component@frontierjs/mesa

One file renders to a page, an email, a fragment or a module. Zero dependencies.

$ npm i @frontierjs/mesa

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.

Replaces

MDX

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.