Converting Bootstraps accordions to a Vue.js component

From time to time I have to use Bootstrap it’s usually on legacy projects as I tend to prefer to use utility based frameworks such as Tailwindcss. In an attempt to make it more easier to create accordions. I decided to rewrite the Bootstrap collapse accordion code into a Vue.js component.

Converting Bootstrap collapse to a VueJS Component

Here is a link of what we aim to have built by the end of this tutorial. Preview or Download

Step 1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Converting Bootstraps accordions to a Vue component</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
</head>

<body>
    <div id="app" class="container" >
        <div class="row justify-content-md-center">
            <accordions>
                <accordion title="Sasuke Uchiha" active="true">
                    <p>Sasuke is introduced in Part I as a young, spiky-black-haired pre-teen wearing a blue shirt with an image of a fan that represents his clan on its back. He also wears short white pants and a Konohagakure headband. Early in the series, Orochimaru brands Sasuke with a Cursed Seal that, when activated, covers his body with black marks and later gives him gray skin, white hair, and claw-like wings. In Part II, he is normally depicted wearing a white kimono and black pants. Although he is skilled in the use of shuriken, in Part II Sasuke uses a chokutō sword that he calls Kusanagi. In addition to using Kusanagi for swordsmanship, Sasuke combines it with lightning-based techniques to increase the power of his attacks. In The Last: Naruto the Movie, his adult wardrobe consists of gray pants and a light-brown cloak over a black shirt, while in Boruto: Naruto the Movie, he wears black pants and a black cape over a lilac vest.</p>
                    <p>Sasuke is a silent character who tries to gain more power and kill his older brother, Itachi, for betraying and murdering their clan. He cares about his teammates and saves them on numerous occasions, but he severs all of his bonds later in Part I, believing this will strengthen him. Sasuke is moved when Naruto Uzumaki wants him to make peace with the village; he considers Naruto his only friend. Sasuke becomes more kindhearted by the end of the series, but he decides not to return home, chooses to redeem himself, and searches for an enemy threatening the peace of Konohagakure.</p>
                </accordion>
                <accordion title=" Naruto Uzumaki">
                    <p>Naruto is an orphan who has a dangerous fox-like entity known as Kurama the Nine-Tailed Fox sealed within his body by his father, the Fourth Hokage Minato Namikaze, the leader of Konoha's ninja force, at the cost of his own life and that of his wife, Kushina Uzumaki. This possession led to Naruto being ridiculed frequently by the rest of Konoha; being associated with him was considered taboo. As a youth, Naruto makes jokes and plays pranks to attract attention. Desiring what he lacked in his early life, Naruto dreams of becoming a Hokage himself with the hope that it will bring him the villagers' recognition and respect. In an attempt to become a ninja, Naruto is horrified to learn of his Jinchuriki nature, but finds acceptance from his teacher Iruka Umino, whom he views as a father. After learning the powerful Multi-Shadow Clone Jutsu, an ability to create physical copies of the user, Naruto becomes a ninja. He joins a ninja group under the leadership of Kakashi Hatake where he gains the friends he lacked during his childhood. These are his classmates who are also assigned to Team 7: Sasuke Uchiha, with whom he has had a rivalry since they first met at the ninja academy, and Sakura Haruno.</p>
                </accordion>
                <accordion title="Kakashi Hatake">
                    <p>Kakashi Hatake is introduced as the Jonin (elite ninja) leader and in charge of Team 7, a new ninja team including Naruto Uzumaki, Sasuke Uchiha and Sakura Haruno. He first appears as a carefree character as he tends to lose track of time, and is frequently late to his appointments as a result.  Kakashi is revealed to be very famous in the Naruto world, earning him the moniker "Kakashi of the Sharingan" for possessing the Sharingan, gaining it from a member of the Uchiha clan he was friends with. It grants him the ability to mimic the movements and jutsu of others. Although most of Kakashi's abilities were acquired with his Sharingan, he also invented the Chidori ("One Thousand Birds") and its Lightning Blade variation, a collection of lightning chakra in one's hand that uses the Sharingan's visual ability to lock onto a target. When first forming Team 7, Kakashi does not turn them into his students until instilling in them the concept of teamwork even if they have to break the rules he gave them. Kakashi continues to further this philosophy for the duration of Part I upon Sasuke Uchiha but is unable to get through to him before the latter's defection from Konoha. Kakashi also reluctantly participates in various kinds of challenges by his childhood friend Might Guy who considers Kakashi his rival. </p>
                </accordion>
            </accordions>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
    <script>
        var app = new Vue({
            el : "#app"
        })
    </script>
</body>
</html>

The follow code is our component which we be creating. In the same snippet of code we also pull in Bootstrap Css, VueJS and set VueJS up on the page.

Step 2

<script>
    Vue.component('accordions', {
        template: `
            <div>
                <div class="accordion" >
                    <slot></slot>
                </div><!-- .accordion -->
            </div>
        `
    });

    var app = new Vue({
        el : "#app"
    })
</script>

We going to create a component called accordions this will be the surrounding wrapper inside it will be the child accordions.

Step 3

<script>
Vue.component('accordions', {
    template: `
        <div>
            <div class="accordion" >
                <slot></slot>
            </div><!-- .accordion -->
        </div>
    `
});

Vue.component('accordion', {
    template: `
        <div class="card">
            <div class="card-header" id="headingOne">
                <h2 class="mb-0">
                    <button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                        {{title}} 
                    </button>
                </h2>
            </div>
            <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
                <div class="card-body">
                    <slot></slot>
                </div>
            </div>
        </div>
    `,
    props: {
        title: {required: true},
        active: {default : false}
    },
});

var app = new Vue({
    el : '#app'
}) 
</script>

We created the accordion component now based on the bootstrap markup. We added in the props for the title which is required. A active state which is set to default if nothing is added. By now the code should now start to resemble a traditional Bootstrap collapse component.

Step 4

Vue.component('accordion', {
    template: `
        <div class="card">
            <div class="card-header" id="headingOne">
                <h2 class="mb-0">
                    <button class="btn btn-link" @click.prevent="accordionToggle" type="button" data-toggle="collapse" data-target="#collapseOne" :aria-expanded="accordionActive" aria-controls="collapseOne">

                        {{title}} 
                    </button>
                </h2>
            </div>
            <div id="collapseOne" v-show="this.accordionActive" aria-labelledby="headingOne" data-parent="#accordionExample">
                <div class="card-body">
                    <slot></slot>
                </div>
            </div>
        </div>
    `,
    data() {
        return { 
            accordionActive : []
        }
    },                
    props: {
        title: {required: true},
        active: {default : false}
    },
    methods : {
        assignPropsToData(){
            this.accordionActive =  this.active;    
        },
        accordionToggle() {
            this.accordionActive = !this.accordionActive;
        }
    },
    created() {
        this.assignPropsToData();
    }                
});

Since it’s best practise not to modify props, we are now going to create a data attribute of accordionActive and assign the active prop value to it. This method will run when the component is created.

Also in the code above we created a method called accordionToggle when someone clicks on the button it will toggle the accordion content using v-show and toggle Aria-expanded attribute.

Step 5

Vue.component('accordion', {
    template: `
        <div class="card">
            <div class="card-header" :id="accordionName">
                <h2 class="mb-0">
                    <button class="btn btn-link" @click.prevent="accordionToggle" type="button" data-toggle="collapse" :data-target="accordionTarget" :aria-expanded="accordionActive" aria-controls="accordionName">
                        {{title}} 
                    </button>
                </h2>
            </div>
            <div :id="accordionName" v-show="this.accordionActive"  :aria-labelledby="accordionName">
                <div class="card-body">
                    <slot></slot>
                </div>
            </div>
        </div>
    `,
    data() {
        return { 
        accordionActive : []
        }
    },
    props: {
        title: {required: true},
        active: {default : false}
    },
    computed : {
        accordionName(){
            return this.title.toLowerCase().replace(/ /g, '-');
        },
        accordionTarget(){
            return '#' + this.title.toLowerCase().replace(/ /g, '-');
        },
    },
    methods : {
        assignPropsToData(){
            this.accordionActive =  this.active;    
        },
        accordionToggle() {
            this.accordionActive = !this.accordionActive;
        }
    },
    created() {
        this.assignPropsToData();
    }
});

Final step we need to name for the ID and the data target. We do this by creating two computed properties. What they do is get the title and of the component and replace the spaces with dashes. The difference between the properties one adds a # symbol the other one doesn’t. We then add the computed properties the relevant attribute.

Summary

As you can see using Vue.js components provides you a way to create a simple API for adding Bootstrap collapsable components.

Leave a Reply

Your email address will not be published. Required fields are marked *