DEV Community

Michael Burrows
Michael Burrows

Posted on • Originally published at w3collective.com

Build an accordion component with Alpine.js

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:

<!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>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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

Next we can start with the accordion component itself:

<div x-data="accordion" class="p-3"></div>
Enter fullscreen mode Exit fullscreen mode

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:

<div x-data="accordion" class="p-3">
  <template x-for="accordion in data" :key="accordion.id"></template>
</div>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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:

<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>
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)