AvalonAvalon
GitHub

Preact

Using Preact components as islands in Avalon.

Setup

Preact is Avalon's default SSR renderer and is always available. No extra configuration needed.

const plugins = await avalon({
  integrations: ['preact'], // optional — included by default
});

Writing a Preact island

Use the /** @jsxImportSource preact */ pragma at the top of your file:

/** @jsxImportSource preact */
import { useState } from 'preact/hooks';

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}

Using the island

import Counter from '../islands/Counter.tsx';

export default function Page() {
  return (
    <div>
      <Counter island={{ condition: 'on:client' }} />
    </div>
  );
}

Signals

Preact Signals work inside islands for fine-grained reactivity:

/** @jsxImportSource preact */
import { signal } from '@preact/signals';

const count = signal(0);

export default function Counter() {
  return (
    <button onClick={() => count.value++}>
      Count: {count}
    </button>
  );
}

Install signals with:

bun add @preact/signals

Why Preact for pages?

Avalon uses Preact for page and layout rendering (not just islands) because it's lightweight and fast on the server. Pages and layouts don't need a pragma — they use Preact's JSX transform automatically.