Introduction

#What is BarefootJS?

BarefootJS is a compiler that transforms JSX components into server-rendered templates and minimal client-side JavaScript.

Write familiar JSX with fine-grained reactivity — the compiler splits it into a server template for your backend and a tiny hydration script for the browser.

"use client"
import { createSignal } from '@barefootjs/dom'

export function Counter({ initial = 0 }) {
  const [count, setCount] = createSignal(initial)

  return (
    <div>
      <p>{count()}</p>
      <button onClick={() => setCount(n => n + 1)}>+1</button>
    </div>
  )
}

This single file compiles into two outputs:

Server template — Renders static HTML with hydration markers:

export function Counter(props) {
  return (
    <div bf-s="Counter">
      <p bf="slot_0">{props.initial ?? 0}</p>
      <button bf="slot_1">+1</button>
    </div>
  )
}

Server template — Go html/template with hydration markers:

{{define "Counter"}}
<div bf-s="{{.ScopeID}}">
  <p bf="slot_0">{{.Initial}}</p>
  <button bf="slot_1">+1</button>
</div>
{{end}}

Client script — Wires up only the interactive parts:

import { createSignal, createEffect, find, bind } from '@barefootjs/dom'

export function hydrate(props) {
  const [count, setCount] = createSignal(props.initial ?? 0)

  const el = find('[bf="slot_0"]')
  createEffect(() => { el.textContent = String(count()) })

  bind('[bf="slot_1"]', 'click', () => setCount(n => n + 1))
}

No framework runtime. No virtual DOM. Just the minimum JavaScript needed for interactivity.

#Why BarefootJS?

#The Problem

Modern frontend frameworks ship large JavaScript runtimes to the browser, even when most of the page is static content. Server-side rendering helps with initial load, but hydration still requires downloading and executing the full framework.

If your backend is Go, Python, or Perl, the gap is wider: you either maintain separate template and JavaScript codebases, or adopt a JavaScript-only stack.

#The BarefootJS Approach

BarefootJS compiles JSX into native templates for your backend and minimal client JS — bridging server rendering and client interactivity without a runtime.

  • Backend agnostic — The same JSX source produces templates for any backend (Go, TypeScript, etc.)
  • Fine-grained reactivity — Signals track dependencies at the expression level, updating only the affected DOM nodes
  • Minimal client JS — Each component ships only the JavaScript it needs, not a framework runtime
  • Full type safety — TypeScript types flow through the entire compilation pipeline

#Design Philosophy

1. Compile, don't ship a runtime. The compiler does the heavy lifting at build time. The browser receives only the JavaScript it needs — no framework, no virtual DOM diffing.

2. Backend agnostic. The same JSX source produces templates for Hono, Go html/template, and any future adapter. Your component library works across stacks.

3. Fine-grained reactivity. Inspired by SolidJS, signals track dependencies at the expression level. When state changes, only the affected DOM nodes update — not the entire component tree.

4. Progressive enhancement. Server-rendered HTML works without JavaScript. Client scripts enhance the page with interactivity. If JavaScript fails to load, users still see content.

5. Familiar syntax, no lock-in. JSX is the authoring format, but the output is standard HTML and vanilla JavaScript. There is no proprietary template language to learn and no framework to migrate away from.

#Who is it for?

  • Full-stack TypeScript developers who want reactive UI without shipping a framework runtime to the browser
  • Backend teams (Go, Python, etc.) who need interactive components without adopting a JavaScript-only stack
  • Performance-focused teams who need minimal client JS with fine-grained DOM updates