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

A plain .tsx file uses Preact when core is "preact" (the default). *.preact.tsx is Preact even when the page shell is React.

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 '../components/Counter.tsx';

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

Signals

Preact Signals work inside islands for fine-grained reactivity:

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

const count = signal(0);

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

Install signals with:

>_ Terminal
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.