On one of my early projects with Alpine.js I needed to pass some structured data about videos to show in a carousel. The data was an array of objects with key/value pairs like:
- Url
- Title
- Description
- Thumbnail image
I was working with PHP on WordPress and the easy solution was to simply pass the data as an argument to the component like this:
<div
x-data='videoCarousel(<?php echo json_encode($video_data); ?>)'
>
…
</div>
This implementation relies on the fact that JSON data is encoded with double quotes around strings so I should be safe using single quotes for the attribute. It worked fine for a while, then one day the page just broke. I of course got a call from the client and looked into it. You may already know what the issue was… they used a single quote in the description which broke the markup.
As a quick, short-term fix, I went in and edited the text to use a curly quote; then I figured out a long term fix. This long term fix became a pattern that I use all the time now: embedding data in a script template and parsing it into my Alpine.js component during init.
Embedding the data for Alpine.js
The simplest version of the embedding code looks like this:
<script type="text/data" x-ref="data"><?php echo json_encode($video_data); ?></script>
There are a few key parts to this:
- We are still outputting JSON-encoded data that we will read in the JS
- The
type
on the script tag istext/data
– with this type the browser will not try to parse and execute the code as JavaScript. The data will just remain present in the page for later use - Assigning an
x-ref
value lets us easily get the data inside the Alpine.js component
Parsing the data in the Alpine component
Here is a subset of the component with the important parts to read the data.
export default () => ({
data: [],
init() {
try {
this.options = JSON.parse(
this.$refs.data.textContent
);
} catch(error) {
// handle exception
console.error("Can't parse data:", error);
}
}
})
How this works:
- The init function is run automatically when the component is loaded
- We use the reference that Alpine.js sets up for us to access the JSON data in the script tag
- The JSON data is parsed and stored in the data property
- Everything is wrapped in a try /catch block for safety – though it’s highly unlikely to be an issue since we control both the embedding and the parsing code
Takeaways
I’ve used this pattern on a number of different projects since then. Some examples include:
- options for a filter control
- content for a quote carousel
- data for a paginated, filterable card list
It’s been a great solution and provides a solid way to pass more complicated data into an Alpine.js component safely.
Want to learn more about using Alpine.js? Check out my new video course: Exploring Alpine.js