React in Astro

Drop a React Component Into an Astro Page

React in Astro

After `npx astro add react`, you can write React components in `.tsx` and use them as Astro components with a `client:*` directive.

4 min read Level 2/5 #astro#react#islands
What you'll learn
  • Author a React component
  • Use it inside an Astro page
  • Hydrate it with a client directive

A React component in an Astro project is just a .tsx file. Use it in .astro files like any other component.

A React Component

// src/components/Counter.tsx
import { useState } from "react";

interface Props {
  initial?: number;
}

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

Use It In An Astro Page

---
import Counter from "../components/Counter.tsx";
---

<h1>Counter Demo</h1>
<Counter client:load initial={5} />

Without client:*, the component renders as static HTML — the button shows but doesn’t react to clicks. The client:load directive ships the React code and hydrates.

Server-Render-Friendly Components

Most React components work out of the box. The exceptions:

  • Components that access window / document during render
  • Components that fetch in a useEffect and break without one
  • Anything that genuinely cannot run in Node

For those, use client:only="react".

Sharing Components Between Astro Sites and React Apps

A .tsx component dropped into Astro is the same component you’d use in a React app. You can move it between projects without changes (assuming the component doesn’t import Astro-specific things, which it shouldn’t).

What Hydration Looks Like in DevTools

Network tab: a small JS file loads when the directive condition fires (immediately for client:load, on idle for client:idle, etc.). Elements tab: the component’s DOM updates to the post-hydration state.

Up Next

What you can — and can’t — pass as props to an island.

Passing Props →