React
Using React components as islands in Avalon.
Setup
Add 'react' to the integrations array in your vite.config.ts:
const plugins = await avalon({
integrations: ['react'],
});
Install the peer dependencies if not already present:
>_ Terminal
bun add react react-dom
File name
Name the file *.react.tsx. Avalon uses that extension to compile the file with React's JSX runtime. A /** @jsxImportSource react */ comment is optional and overrides the filename.
Writing a React island
// src/components/Counter.react.tsx
import { useState } from 'react';
export default function Counter({ initialCount = 0 }: { initialCount?: number }) {
const [count, setCount] = useState(initialCount);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
Using the island
import Counter from '../components/Counter.react.tsx';
export default function Page() {
return (
<div>
<Counter initialCount={5} island={{ condition: 'on:interaction' }} />
</div>
);
}
Server rendering
React islands are server-rendered to HTML by default using react-dom/server. The client bundle only loads when the hydration condition is met.
Hooks and context
All React hooks work inside islands. Context providers must live inside the island itself — they cannot span across multiple islands.
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
export default function ThemedApp() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Toggle theme
</button>
</ThemeContext.Provider>
);
}
Caveats
- Hooks work —
useState,useEffect,useRef,useMemo, and all other React hooks work as expected inside islands. - No signals — React does not have a signals primitive. Use
useStateoruseReducerfor local state, anduseContextfor shared state within an island tree. - Context cannot span islands — A
Context.Providerin one island cannot provide values to a different island. Each island is an independent React tree. For live updates across islands, use DOM CustomEvents; avoid module-level singleton stores that can leak on the server during SSR.