Build an accordion component with Alpine.js
Tags: javascript, tutorial, alpinejs
Published: 2023-03-03 01:21:01

In this tutorial we’ll be using Alpine.js to build an accordion component. Accordions or collapsible panels as they’re also known are used to hide and show large amounts of content by clicking a heading. Please note, to keep this tutorial Alpine focused I’ve used the Tailwind CSS framework but it could easily be converted to plain CSS.

Let’s get started by creating a new HTML file and loading Alpine and Tailwind via CDN:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Alpine.js Accordion</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" />
    <script src="https://unpkg.com/alpinejs" defer></script>
  </head>
  <body>
  </body>
</html>
```

Now for the accordion data which is stored in an array as follows:

```javascript
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('accordion', () => ({
            data: [
            {
                id: '1',
                heading: 'What is Alpine.js?',
                content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis pharetra dui, ac feugiat metus. Vivamus id pellentesque urna, quis hendrerit tortor. Sed pharetra sapien a metus fringilla varius.',
                isOpen: false,
            },
            {
                id: '2',
                heading: 'Is Alpine.js better than jQuery?',
                content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis pharetra dui, ac feugiat metus. Vivamus id pellentesque urna, quis hendrerit tortor. Sed pharetra sapien a metus fringilla varius.',
                isOpen: false,
            },
            {
                id: '3',
                heading: 'Who created Alpine.js?',
                content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis pharetra dui, ac feugiat metus. Vivamus id pellentesque urna, quis hendrerit tortor. Sed pharetra sapien a metus fringilla varius.',
                isOpen: false,
            },
            ]
        }))
    });
</script>
```

The `eventListener` here is waiting for Alpine to load before creating a data object.

Next we can start with the accordion component itself:

```html
<div x-data="accordion" class="p-3"></div>
```

Components in Alpine always have the `x-data` directive which defines a section of HTML as an Alpine component. It also provides the reactive data for a component to reference, in our case the `accordion` data created in the previous step.

We’ll use the `<template>` element for holding the HTML as it isn’t be rendered immediately:

```html
<div x-data="accordion" class="p-3">
  <template x-for="accordion in data" :key="accordion.id"></template>
</div>
```

Alpine’s `x-for` directive iterates through the data to create the following markup:

```html
<div x-data="accordion" class="p-3">
  <template x-for="accordion in data" :key="accordion.id">
    <div class="accordion">
      <button @click="data = data.map(i => ({ ...i, isOpen: i.id !== accordion.id ? false : !i.isOpen}))"
        class="w-full flex justify-between items-center border-b py-3">
        <h3 x-text="accordion.heading" class="font-bold"></h3>        
      </button>
      <div x-text="accordion.content" x-show="accordion.isOpen" class="py-3"></div>
    </div>
  </template>
</div>
``` 

When the button is clicked the `isOpen` value is toggled between `true` and `false`. The `x-text` directive gets the accordion content and displays it within the element it reside. The final piece of Alpine used is `x-show` which controls the visibility on and element so only when `accordion.isOpen` equals `true` is the content visible.

Finally let’s add an icon to indicate whether or not the accordion is open or closed:

```html
<div class="accordion">
  <button @click="data = data.map(i => ({ ...i, isOpen: i.id !== accordion.id ? false : !i.isOpen}))"
      class="w-full flex justify-between items-center border-b py-3">
      <h3 x-text="accordion.heading" class="font-bold"></h3>
      <span x-show="accordion.isOpen">-</span>  
      <span x-show="!accordion.isOpen">+</span>            
  </button>
  <div x-text="accordion.content" x-show="accordion.isOpen" class="py-3"></div>
</div>
```

Once again we’ve used `x-show` to control the visibility of the open and closed icons based on the value of `accordion.isOpen`.

That’s all for this tutorial, you should now have a fully functioning accordion component powered by Alpine.js. If you enjoyed this tutorial you may also be interested in some of our other [Apline.js tutorials](https://w3collective.com/tag/alpine/).