- i only speak liquid
- Posts
- "i only speak liquid" #74: Accessible Interactivity: Alpine.js + Liquid
"i only speak liquid" #74: Accessible Interactivity: Alpine.js + Liquid
Written by Kenny (a Storetasker Expert)
Hey everyone,
Woohoo! This is Kenny’s 2nd of 4 edits of “i_only_speak_liquid” 🔥🔥🔥
A bit about Kenny:
Kenny’s a shopify developer, who ex-Bondfire agency. He’s based out of LA & has built beautiful sites like Rishi Tea, Imogene + Willie & Body Bio.
Let’s GO 📚
What I’ve been thinking about:
As Shopify developers, it’s our responsibility to ensure that the theme’s we build can be used by everyone. If you're new to developing with accessibility in mind, managing ARIA attributes, roles, keyboard navigation, and focus behavior can feel quite daunting. Enter Alpine.js - a lightweight javascript framework for composing behavior directly in your markup, and in our case, directly within liquid templates (thank you Caleb Porzio!). While I’m a huge fan of Alpine for many reasons, in this article, I thought I’d highlight how easy it can make creating accessible UI.
First things first, you need to install Alpine in your project. I won’t go into details, but you can refer to Alpine’s documentation here. I’ll also be discussing the Focus plugin. You can find the documentation for that here.
Let’s take a look at an example of a dropdown navigation menu to show how simple it is to manage aria attributes and focus with Alpine.
Basic HTML & Alpine Setup
<nav x-data="{ open: false }">
<button
@click="open = !open"
:aria-expanded="open"
aria-haspopup="menu"
aria-controls="dropdown-menu"
class="nav-button"
>
Menu
</button>
<ul
id="dropdown-menu"
role="menu"
x-show="open"
x-trap="open"
@keydown.escape.window="open = false"
@click.outside="open = false"
class="dropdown-menu"
>
<li><a href="/" role="menuitem">Home</a></li>
<li><a href="/collections" role="menuitem">Collections</a></li>
<li><a href="/about" role="menuitem">About</a></li>
</ul>
</nav>
Understanding the Alpine.js Syntax
x-data: Initializes a new Alpine component, holding the reactive state. Here, it's used to track whether the dropdown menu (open) is visible or hidden.
@click: Sets up an event listener for clicks. In our case, it toggles the dropdown’s visibility by changing the value of open.
x-show: Conditionally shows or hides an element based on a state variable. In this example, it reveals the dropdown menu only when open is true.
@click.outside: Detects clicks outside the specified element and updates the Alpine state
Accessibility Enhancements
:aria-expanded: The colon (:) before aria-expanded indicates that it is dynamically bound to the Alpine state. It automatically updates based on the value of open, clearly communicating the dropdown’s visibility state to assistive technology.
aria-haspopup: Communicates to assistive technology that the button triggers additional interactive content.
aria-controls: Clearly indicates the element controlled by the button, helping screen readers understand the relationship.
x-trap: Automatically traps keyboard navigation within the dropdown when open, ensuring users can't accidentally navigate away and get lost on the page. I’ve used this on tons of primary navigation menus, custom cart drawers, modals, etc.
@keydown.escape.window: Enables users to close the menu using the escape key.
Why Alpine Works Great with Liquid
Alpine works great with Shopify themes because of its minimal setup, tiny footprint, and straightforward syntax. It’s the perfect complement to Liquid. It makes it incredibly easy to handle user interactions and manage state in your UI. Once you’ve got the basics down, you can go pretty deep with Alpine by incorporating stores, custom directives, magics, and the rest of the available plugins.
3 links you can’t miss:
📌 Alpine JS: If you couldn’t already tell, I am a big fan
📌 Syntax FM w/ Caleb Porzio: Episode of the Syntax Podcast with guest Caleb Porzio, creator of Alpine JS
📌 Run Studio Run by Eli Altman: Great book about running a small studio. Geared toward studio owners but lots of great insights for freelancers to improve their processes.
1 app I like:
Matrixify: A powerful tool for bulk importing, exporting, and managing data in Shopify. It significantly streamlines large data migrations and product updates, saving considerable time and effort. I just finished a custom theme that has individual storefront for the US and the UK. We used a lot of metaobjects in the build and Matrixify played an essential role in copying them over from one store to the other.
One learning as a freelancer:
Accessibility adds value. Clients increasingly value accessibility—not only as a compliance necessity but as a reflection of their brand values. Positioning yourself as a developer who understands accessibility can significantly set you apart. During scoping conversations, I like to make it known that I have acted as the engineering lead on ADA audits for clients in the past. If you can tackle a significant percentage of common accessibility during your initial build, you are saving the client time, energy and money down the line. If you’re trying to value-price your projects, it can help you capture the project at a higher premium.