SolidJS Islands
Islands are interactive SolidJS components embedded in server-rendered HTML. They let you add client-side interactivity exactly where you need it.
How Islands Work
- Create a TSX component in
client/ - Use the
island!macro in Rust to place it - Rejoice renders a placeholder
<div data-island="..."> - Client-side JavaScript hydrates the component
Creating an Island
Create a component in client/:
client/Counter.tsx:
import { createSignal } from "solid-js";
interface CounterProps {
initial: number;
label?: string;
}
export default function Counter(props: CounterProps) {
const [count, setCount] = createSignal(props.initial);
return (
<div class="counter">
<span>{props.label || "Count"}: {count()}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
<button onClick={() => setCount(c => c - 1)}>-</button>
</div>
);
}
Important: Export the component as default.
Using an Island
Use the island! macro in your Rust templates:
use rejoice::{Req, Res, html, island};
pub async fn get(req: Req, res: Res) -> Res {
res.html(html! {
h1 { "Interactive Counter" }
// Island with props
(island!(Counter, { initial: 0 }))
// Island with multiple props
(island!(Counter, { initial: 10, label: "Score" }))
})
}
Props Syntax
// No props
(island!(SimpleComponent))
// Single prop
(island!(Counter, { initial: 42 }))
// Multiple props
(island!(UserCard, {
id: 123,
name: "Alice",
active: true
}))
// Dynamic values
let user_id = 123;
(island!(UserCard, { id: user_id }))
File Naming
- Files must be in
client/directory - Use
.tsxor.jsxextension - Component name matches filename:
Counter.tsx→Counter - Export as
default islands.tsxis auto-generated (don't edit)styles.cssis for Tailwind (not a component)
Islands Registry
The file client/islands.tsx is automatically generated. It:
- Imports all component files
- Creates a registry mapping names to components
- Handles hydration when the page loads
- Exposes
window.__hydrateIslands()for live reload
Never edit this file manually. It's regenerated on every build.
Styling Islands
Islands can use Tailwind classes just like your Rust templates:
export default function Card(props: { title: string }) {
return (
<div class="bg-white shadow-lg rounded-lg p-6">
<h2 class="text-xl font-semibold">{props.title}</h2>
</div>
);
}
Tailwind scans both src/**/*.rs and client/**/*.tsx for class names.
When to Use Islands
Use islands for:
- Interactive UI (buttons, forms, toggles)
- Client-side state (counters, carts, filters)
- Real-time updates (live data, notifications)
- Complex animations
Don't use islands for:
- Static content (use server-rendered HTML)
- Content that doesn't need interactivity
- SEO-critical content
Server-First Philosophy
Rejoice is server-first. Start with server-rendered HTML, then add islands only where needed. This gives you:
- Fast initial page loads
- Works without JavaScript
- Better SEO
- Smaller bundle sizes
Next Steps
- Tailwind CSS - Style your islands and pages
- Templates - Server-rendered HTML with Maud