Run Alpine.js inside of React
Alpine.js is well-suited for building widgets and easily creating client-side experiences for websites that are mainly server-side rendered or static.
Good news: it is possible (at the time of writing with Alpine.js 2.x) to integrate Alpine.js with React trivially.
Alpine.js is “A rugged, minimal framework for composing JavaScript behavior in your markup.”. It can be included simply with a script
tag from a CDN and weights in under 5kb.
Caleb Porzio, Alpine.js’ creator, likens it to “Tailwind for JavaScript”.
Now one of the great things about Tailwind is that the examples provided are very much copy-pasteable.
If Alpine.js widgets ever pick up, integrating them in a React application might be useful.
In this post we’ll see how to run Alpine.js inside of a React application.
To see the full demo/code repo head to github.com/HugoDF/react-alpinejs.
Table of Contents
Introduction & Setup
To integrate Alpine.js and React we’ll need a project where both are installed. For a minimal React project setup I use Parcel as per github.com/HugoDF/react-minimal-starter-parcel.
On top of that we’ll need to install alpinejs
(the starter project comes with react
, react-dom
and parcel-bundler
).
yarn add alpinejs
Next, Alpine.js needs to be included in the bundle, in main.js
we can add an import.
import React from 'react';
import 'alpinejs';
// Rest of React App/ReactDOM setup code.
There are a few gotchas to using Alpine.js inside of a React project.
Register x-data and x-init functions as window
properties
Alpine.js looks for x-init
and x-data
functions on the global scope (ie. window
). By default, bundlers will scope the functions to the current module (instead of window
).
That means you’ll need to define your functions as window
properties, like so:
// main.js, imports are omitted for brevity.
window.counter = function() {
return {
count: 0,
inc() {
this.count += 1;
}
};
};
Note: arrow functions also work.
Use a template string + dangerouslySetInnerHTML to render Alpine.js templates
React/JSX/Parcel/Webpack don’t like :
, you’ll get Namespace tags are not supported by default. React's JSX doesn't support namespace tags.
when trying to use x-on:eventType
event bindings or the shorthand for property bindings (without x-bind
eg. :key
). @
which is used as shorthand for x-on:
is also invalid.
In order to render an Alpine.js template, we need to avoid the JSX compiler. In order to do this, we can make the template a string:
// main.js
// imports and window.counter definition omitted
const alpineTemplate = `<div x-data="counter()">
<button @click="inc()">Increment</button>
<p x-text="count"></p>
</div>`;
// ReactDOM bootstrap omitted
This way, @
and :
don’t cause any issues.
To render this template, we’ll now dangerouslySetInnerHTML
to this HTML string.
// main.js
// imports and window.counter definition omitted
const AlpineWidget = () => (
<div dangerouslySetInnerHTML={{__html: alpineTemplate}} />
);
const App = () => (
<>
<h2>Running Alpine.js inside React</h2>
<AlpineWidget />
</>
);
// ReactDOM bootstrap omitted
Putting this all together gets us our Alpine.js counter widget rendering from inside a React application.
Interested in Alpine.js?
Subscribe to Alpine.js Weekly. A free, once–weekly email roundup of Alpine.js news and articles