· Experiences  · 2 min read

Reactivity in Astro

As I was learning to use the Astro framework, I wanted to learn about idiomatic implementations within Astro. Here is what I learned about implementing reactivity in Astro.

As I was learning to use the Astro framework, I wanted to learn about idiomatic implementations within Astro. Here is what I learned about implementing reactivity in Astro.

While using Astro, I liked how the HTML and CSS can be dynamically generated, however, I hit an issue when building reactive components:

---
function onclick() {
console.log('clicked')
}
---

<button onclick="{onclick}">Test</button>

Having lived in both svelte and react, you may have expected the above Astro code to be correct and functional. However, the Frontmatter --- fence is purely there for the separation of server-side and client-side code only. Astro does not expose server-side functions to the client, even if they are referenced.

There are a few ways to solve this. On my journey, I had reviewed that Astro has great integrations with a client-side framework, knowing that they did not have strong reactivity support, so I tried adding Vue to my stack.

<script lang="ts" setup>
  function onclick() {
    console.log('click');
  }
</script>

<template>
  <button @click="onclick">Test</button>
</template>

Although this added reactivity, the syntax difference made it awkward to work with both Vue and Astro. Also, adding the client-side framework also increased my build times on every change since we also had to trigger the framework transpilation. But the biggest problem that I ran into, was an issue where Vue components cannot import Astro components, even though Astro components can import Vue components. In my exploration, I learned that this was also true when trying to integrate Svelte.

The solution was to RTFM and actually learn to work within Astro. I read common script patterns and learned that you need to add a client-side script and work within the browser’s JavaScript. I wasn’t ready to jump back into the raw wild west since I was already invested in the Astro framework. Reading on, I found my answer with Astro web components. This is using the web components api to create custom html elements to bind reactivity. You can still bind Astro server-side properties to these web components.

---
const { message = 'clicked' } = Astro.props;
---

<astro-button>
  <button>Test</button>
</astro-button>

<script define:vars="{{" message }}>
  class AstroButton extends HTMLElement {
    // Handle all reactivity in the connected callback
    connectedCallback() {
      const button = this.querySelector('button');
      button.addEventListener('click', () => {
        console.log(message);
      });
    }
  }

  customElements.define('astro-button', AstroButton);
</script>

Final Thoughts

It took some time to understand the point of view of Astro on reactivity. Although Astro web components do have a little more boilerplate than Vue and Svelte, it is compact and simple enough to handle my logic and reactivity.

Back to Blog

Related Posts

View All Posts »
Choosing a Framework for My Static Site

Choosing a Framework for My Static Site

There are so many frameworks for starting a site. I went on a journey to find the right framework to build a home for Sea Otter Studios. Here are the reasons why I ended up choosing Astro.

© 2025 Sea Otter Studios All rights reserved.