How to create a simple accordion menu with Nuxt.js
By: Megan Tipps
Tags: Vue, Accordion, Nuxtjs, Nuxt, Vuejs

Creating the accordion menus

In your IDE have a look at the project structure. I am not going to go into detail about this, but have a look at the docs for more information (https://nuxtjs.org/guide/directory-structure).

We will be using the index.vue file under the pages directory, as seen at http://localhost:3000/.

index.vue file we will be using

Cleanup this file by removing all the code and replacing it with:

<template>

<div></div>

</template> <script>

export default {



}

</script>

Now that we have a blank slate lets add the data for our accordion menu, by replacing the code in the script tags with:

<template>

<div></div>

</template>

<script>

export default {

data () {

return {

harryPotterCharacters: [

{

characterName: 'Harry Potter',

characterShortBio: 'Harry James Potter (b. 31 July 1980) was an English half-blood wizard, one of the most ' +

'famous wizards of modern times. He was the only child and son of James and Lily Potter (née Evans), ' +

'both members of the original Order of the Phoenix. Harry\'s birth was overshadowed by a prophecy, ' +

'naming either himself or Neville Longbottom as the one with the power to vanquish Lord Voldemort. ' +

'After half of the prophecy was reported to Voldemort courtesy of Severus Snape, Harry was chosen as the ' +

'target due to his many similarities with the Dark Lord. This caused the Potter family to go into hiding. ' +

'Voldemort made his first vain attempt to circumvent the prophecy when Harry was a year and three months old. ' +

'During this attempt, he murdered Harry\'s parents as they tried to protect him, but this unsuccessful ' +

'attempt to kill Harry led to Voldemort\'s first downfall. This downfall marked the end of the First ' +

'Wizarding War, and to Harry henceforth being known as the "Boy Who Lived."'

},

{

characterName: 'Hermione Granger',

characterShortBio: 'Hermione Jean Granger (b. 19 September, 1979) was an English Muggle-born witch born to ' +

'Mr and Mrs Granger. At the age of eleven, she learned about her magical nature and had been accepted into ' +

'Hogwarts School of Witchcraft and Wizardry. Hermione began attending Hogwarts in 1991 and was Sorted into ' +

'Gryffindor House. She possessed a brilliant academic mind and proved to be a gifted student in almost ' +

'every subject that she studied.'

},

{

characterName: 'Ron Weasley',

characterShortBio: 'Ronald Bilius "Ron" Weasley (b. 1 March, 1980) was an English pure-blood wizard, the ' +

'sixth and youngest son of Arthur and Molly Weasley (née Prewett). He was also the younger brother of ' +

'Bill, Charlie, Percy, Fred, George, and the elder brother of Ginny. Ron and his brothers and sister ' +

'lived at the Burrow, on the outskirts of Ottery St Catchpole.'

}

]

}

}

}

</script>

What we did: We created a simple array of objects, and each item holds the characters name and a short biography.

Now it does not look like we have done much, but your data is available immediately. Install Vue Devtools for either Chrome or Firefox by going to https://github.com/vuejs/vue-devtools. Once installed, you can open the browser developer tools as per usual, and you will now see you have a new option called Vue. Once you open it and continue through the structure, you will see your array of Harry Potter characters on the right.

Vue developer tools with our array of data

Now to show your data without us having to go into the developer tools change the code in your template tag with the following:

<template>

<div class="m-20">

<div

v-for="(character) in harryPotterCharacters"

:key="character.characterName"

>

<p class="bg-gray-800 text-white p-6 cursor-pointer">

{{ character.characterName }}

</p>

<div class="bg-gray-100 p-6">

<p>{{ character.characterShortBio }}</p>

</div>

</div>

</div>

</template>

What we did: We updated a simple div with a v-for, so we can loop through our array of objects and then display the relevant data. I also added some Tailwind CSS classes to make it look a bit more pleasant.

The start of our accordion menu

Now for the functionality to open and close the accordion items, we start by changing our code in the template tag to the following:

<template>

<div class="m-20">

<div

v-for="(character, index) in harryPotterCharacters"

:key="character.characterName"

>

<p class="bg-gray-800 text-white p-6 cursor-pointer" @click="characterItemClick(index)">

{{ character.characterName }}

</p>

<div :data-character-id="index" class="bg-gray-100 p-6">

<p>{{ character.characterShortBio }}</p>

</div>

</div>

</div>

</template>

What we did:

We have now added an index in the v-for. The index will automatically assign the correct index number of the accordion item. We added a click event listener to our character name div. When you click the character, it will pass the accordion item index which lets us know which character biography to show. We add this to our div that contains the character biography via a data attribute called data-character-id. We will now be able to know which div to look for when the character gets clicked.

For the click listener to work, we need to add the event in methods, after your ending curly brace for your data() in the script tag add a comma and the following:

methods: {

characterItemClick (characterIndex) {

const characterInfoElement = document.querySelectorAll('[data-character-id="' + characterIndex + '"]')[0]

if (characterInfoElement.classList.contains('block')) {

characterInfoElement.classList.remove('block')

characterInfoElement.classList.add('hidden')

} else {

characterInfoElement.classList.remove('hidden')

characterInfoElement.classList.add('block')

}

}

}

What we did: We are searching the whole document for the data attribute called data-character-id with the index that we passed through. We then check to see if it is hidden or not. We then add and remove classes on that element. Please note, I am using standard Tailwind CSS classes for display: none and display: block. If you did not choose to use Tailwind CSS, then you will have to create these classes on your own in style tags at the bottom of the page.

When you now go to http://localhost:3000/, you will have a functioning accordion menu with each item working on their own to open and close.

Here you can see the index.vue file as a whole.