Framework Integrations
Bring your own framework
Section titled “Bring your own framework”Astro doesn’t have its own client-side component runtime — instead it lets you use the UI framework you already know for the interactive bits. React, Vue, Svelte, Solid, and Preact all work as islands, via official integrations.
You add an integration with the CLI, which installs the package and wires up the config:
npx astro add reactThat updates astro.config.mjs for you:
import { defineConfig } from 'astro/config';import react from '@astrojs/react';
export default defineConfig({ integrations: [react()],});Now a .jsx component can be imported into an .astro file and hydrated with a client directive.
Importing a framework component as an island
Section titled “Importing a framework component as an island”The island is written in the framework’s normal style; the .astro file imports it and decides when it hydrates.
// src/components/Counter.jsx — a plain React componentimport { useState } from 'react';
export default function Counter({ start }) { const [count, setCount] = useState(start); return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;}---import Counter from '../components/Counter.jsx'; // 1. import the framework component---<h1>Welcome</h1><Counter start={0} client:visible /> <!-- 2. hydrate it as an island -->Without the client:visible, that Counter would render as static HTML (the button, but no working onClick). The directive is what ships its JavaScript.
Mixing frameworks on one page
Section titled “Mixing frameworks on one page”Because each island is independent, you can use different frameworks on the same page — a React widget next to a Svelte one — as long as both integrations are installed. This is genuinely useful for incremental migration or for dropping in a component that only exists in one ecosystem.
flowchart TB page["Astro page (static HTML)"] page --> r["React island — client:load"] page --> s["Svelte island — client:visible"] page --> v["Vue island — client:idle"]
Props must be serializable
Section titled “Props must be serializable”When you pass props from an .astro file into an island, they are rendered on the server and serialized into the HTML so the client can rehydrate with the same values. That imposes one hard rule: island props must be serializable — strings, numbers, booleans, arrays, plain objects. What you cannot pass:
- Functions (including event handlers). There’s no way to serialize a function across the server/client boundary.
- Class instances,
Dateobjects in some cases, and other non-plain values.
---import Chart from '../components/Chart.jsx';const data = await getMetrics(); // fetched on the server---<Chart data={data} client:visible /> <!-- fine: data is a plain array/object --><!-- <Chart onPoint={(p) => ...} /> — NOT allowed: functions cannot be serialized -->If you need behavior instead of data, put that logic inside the island, or pass server-rendered children through a slot (covered next lesson). The framing that keeps you out of trouble: an .astro file hands an island data, not callbacks.