astro-islas-ui-frameworks

UI Integrations - Using React, Vue, and Svelte in Astro

  • 5 min

So far, we have treated Astro as a static site generator. That is, we have used Astro components, routing, and Markdown to generate static content.

But the JavaScript ecosystem is vast. You probably already have a React component library you love, a complex calendar built in Vue, or simply prefer Svelte’s reactivity for certain interactions.

Do we have to rewrite everything to use Astro? Not at all. You can bring your own components from your favorite framework and Astro will render them.

The “Bring Your Own Framework” Concept

Astro tries not to reinvent the wheel of reactivity. Instead of creating its own complex client-side state management engine (like React’s Virtual DOM), Astro allows you to use the engines that already exist.

You can use React / Preact, Vue, Svelte, SolidJS, AlpineJS… almost any Framework you can think of. And most impressively: you can use them all at once on the same page.

Although, for the sake of your mental health (and performance), I recommend you don’t go overboard mixing libraries wildly.

Installing Adapters

For Astro to understand a React or Vue component, we need to install its corresponding adapter.

As we saw in the previous article with Tailwind, we will use the astro add command.

For example, with React we would open the terminal and run:

npx astro add react
Copied!

The Houston assistant will perform the following tasks:

  1. Install @astrojs/react and react / react-dom.
  2. Configure tsconfig.json to support JSX ("jsx": "react-jsx").
  3. Add the integration to astro.config.mjs.

If it were another framework like Vue or Svelte, the process is identical:

npx astro add vue
# or
npx astro add svelte
Copied!

Once finished, if we look at our astro.config.mjs, we will see something like this:

import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';

export default defineConfig({
  // We can have multiple integrations at once!
  integrations: [tailwind(), react()],
});
Copied!

Creating Our First Framework Component

Let’s create a classic component: a Counter in React (boring as it is, but it’s the “hello world” of reactivity).

We’ll create it in the src/components/ folder, but this time with the .jsx extension (or .tsx if you use TypeScript).

src/components/Contador.tsx
import { useState } from 'react';

export default function Contador() {
  const [cuenta, setCuenta] = useState(0);

  return (
    <div className="p-4 border rounded bg-white shadow">
      <p className="text-xl mb-2">Cuenta actual: {cuenta}</p>
      <button 
        className="bg-blue-500 text-white px-4 py-2 rounded"
        onClick={() => setCuenta(cuenta + 1)}
      >
        Sumar +1
      </button>
    </div>
  );
}
Copied!

It’s a standard React component. There’s nothing specific to Astro in this code.

Rendering the Component in Astro

Now we go back to one of our pages, for example src/pages/index.astro, and import the component.

src/pages/index.astro
---
import Layout from '../layouts/Layout.astro';

// We import the React component just like an Astro one
import Contador from '../components/Contador.tsx';
---

<Layout title="Probando React">
  <h1>Testing Integrations</h1>
  
  <p>Below you will see a React component:</p>

  <Contador />

</Layout>
Copied!

The “Trick” of Static Rendering

If you save the file and go to the browser, you will see the counter. You will see the blue button. But if you click the button, nothing will happen!

Is it broken? Did we configure React wrong? No. Welcome to Astro’s philosophy.

By default, Astro renders UI components (React, Vue, etc.) only on the server (Server Side Rendering - SSR).

That is, what is happening is:

Astro executes the React code in the backend during compilation.

React generates the resulting HTML (<div>...Count: 0...</div>).

Astro takes that HTML, injects it into the page, and sends it to the user.

Astro removes the React JavaScript.

This is “Zero JS by default”. Astro assumes that, unless you tell it otherwise, you only want to use React as a templating engine to generate nice HTML, not for interactivity.

This feature is great for components like Headers, Footers, or Sidebars. You can build them in React with all its power, but the user receives pure HTML without the weight of the React library.

How Do I Make the Button Work?

Now you might be wondering:

Wonderful static HTML, Luis, but I want the button to add

Ok, ok. 👍. For the component to “come alive” in the browser and be interactive, we need to explicitly tell Astro to load the JavaScript.

This process is called Hydration.

Astro uses a system of Hydration Directives (client:*) to control this behavior with surgical precision.

But this is such an important topic that it has its own article. In the next installment, we will see how to “awaken” our Islands of interactivity.