An Alternative Approach to Computed Properties in Alpine.js

I previously wrote about using functions as computed properties in Alpine, but what if there was a better way?

Published 2 months ago | Updated 2 months ago

The other day, I wrote an article on how to achieve a similar effect to computed properties in Alpine.js. The approach that I took involved simply calling a method that returned a value:

<div x-data="data()">
    <span x-text="hello()"></span>
</div>

<script>
function data() {
    return {
        hello: function () {
            return "Hello!"
        }
    }
}
</script>

This works quite well, but they're not really properties anymore. The <span> is still reactive, so if the return value depended on another data property, the UI would be updated when the dependency gets changed. To my eyes, property() isn't as pretty as property on it's own.

Today though, I saw a tweet from Sebastian De Deyne that took a different approach to the same concept.

This approach just didn't occur to me at first. It's probably because I hadn't actually tried it. The first thing I did was hop into CodePen and try it out:

See the Pen Getters Alpine.js by Ryan Chandler (@ryangjchandler) on CodePen.

Out of the box, it just works! Click the button on the right and watch the <span> below update. I almost feel kind of stupid that I hadn't though of this originally. Since Alpine is using an object literal as it's source of data, we can use all of the normal things an object provides, such as getters and setters.

The other added benefit this method provides is that you don't need to add the parentheses anymore because when Alpine tries to access the property, the JavaScript engine will recognise that there is a getter defined and call that for us.

Browser compatibility

Regular getters and setters are supported in all modern browsers and ... 🥁 all the way back to Internet Explorer 9. The only thing that isn't supported that far back is computed property names, so you can't do things like:

function data() {
    return {
        get [expression]() {
            return 'Hello!'
        }
    }
}

The expression is dynamic and acts like a fallthrough if the property doesn't exist or doesn't have a getter defined already. That's not a big deal, because nobody should be using IE9 today. Seriously, nobody.

Sign off

Thanks to Sebastian for tweeting about this. You can read some of his blog posts on his personal blog too.

Personally I'm going to be using this approach going forward, especially since the browser support is so good (unusual, I know).