Create Dynamic Drop-down component with Vue 3, Tailwind CSS and Laravel 9
Tags: laravel, vue, tailwindcss, tutorial
Published: 2022-02-09 11:40:38

## Good day everyone 👋

In this article i'm going to explain how to build a fully dynamic drop-down VueJS 3 component with HTML, Tailwind CSS 3 and Laravel 9. We will use composition API which was introduced in the latest version of Vue, our drop-down's content will be looping over Mysql database so it's a dynamic component and also we will introduce Vue3 click-outside npm package to close the drop-down when the user clicks anywhere else on the screen.

### By the end of this 2 parts series you will be able to build this:

{% vimeo 676584884 %}

## Table of Content:
  * [0- What will You Learn?](#chapter-1)
  * [0- Tools](#chapter-2)
  * [1- Install Nodejs and npm](#chapter-3)
  * [2- Start your Laravel Project](#chapter-4)
  * [3- Install Database Management Tool](#chapter-5)
  * [4- Create a Database](#chapter-6)
  * [5- Connect to Database](#chapter-7)
  * [6- Create fake users & Migrate with seed](#chapter-8)
  * [7- Install Tailwind CSS](#chapter-9)
  * [8- Install Vue and it's dependencies](#chapter-10)
  * [9- Prepare your blade file](#chapter-11)
  * [10- Enable Vue and make component](#chapter-12)
  * [11- Build the Drop-down](#chapter-13)
  * [12- Vue JS 3 click outside](#chapter-14)
  * [13- Loop over users in Database](#chapter-15)
  * [14- Finishing](#chapter-16)

### By the end of this tutorial, you should know the below by heart ❤️: <a name="chapter-1"></a>

- How to install Node and npm.
- How to create new Laravel 9 project.
- How to create and connect to a database.
- How to seed fake users to database.
- How to install tailwind CSS.
- How to install Vue, Vue Router and Vue Loader and activate them.
- How to prepare your blade file to receive your component via Vue-router
- How to make a dynamic drop-down vue js 3 component using composition API and click-outside package and style it with Tailwind CSS 3.
- How to receive Json data from database via route and loop over them with axios in Vue component.

A piece of advice before starting, this is a step by step guide so it's better if you code along as we will be using multiple frameworks and techniques. Let's get to it? 👇

### 0- I'm using <a name="chapter-2"></a>

1- npm & Node
2- Laravel 9 🥳
3- Table plus
4- Tailwind CSS 3
5- Vue JS 3 (With Vue Router & Vue Loader)
6- Windows Terminal
7- VS Code


### 1- Install Nodejs and npm: <a name="chapter-3"></a>

- First thing you need to make sure that you have Node and npm installed on your machine.
- You can check that by opening up the terminal and type those two commands: 

npm -v
node -v
 
- If you need to install them 🔗 [DOCs for downloading Node and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
- If you got that converged, move on 👇

```winbatch
PS C:\Users\Moose> node -v
v16.13.2
PS C:\Users\Moose> npm -v
8.4.0
```

### 2- Start your Laravel Project: <a name="chapter-4"></a>

- If you already have a project, you can skip this step 👇.
- I use composer to create Laravel projects.
- You can download composer from here: https://getcomposer.org/
- Open up your terminal and create your Laravel project in the desired directory.
- The below command will create new Laravel 9 project for us.

```winbatch
PS C:\Users\Moose> cd F:\Projects
PS F:\Projects> composer create-project laravel/laravel dropdown-component
```

### 3- Install Database Management Tool: <a name="chapter-5"></a>

- I use free version of table plus to manage my databases.
- You can download it from here: https://tableplus.com/
- This really doesn't require any instructions, keep clicking next and leave everything to default settings.
- You don't have to use it if you prefer another database management tool.

### 4- Create a Database: <a name="chapter-6"></a>

- I will use MySQL Database. You're free to use whatever database you like.
- There are many ways to create Mysql Database, to know more you can visit [**this link**](https://www.mysqltutorial.org/mysql-create-database/).
- I will create a database using MySQL Command Line Client and name it '**dropdown**'.

`mysql> create database dropdown;`

### 5- Connect to Database: <a name="chapter-7"></a>

- Open your Laravel project in the preferred code editor, in my case I will use VS Code.
- Head to your `env` file in the main Laravel project directory.
- In the below section make sure to update all the info to match your created database.

![env file screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khtvbgq64fiyp5kz39e0.png)

- Open table plus -> click on 'Create new connection' -> MySQL.
- Fill in the fields with the info you just created.
- You can name the connection with anything you want.
- After filling the fields click test then connect.

![Table plus connect layout](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xfesgrwle9qfdc8lq0f7.png)

### 6- Create fake users & Migrate with seed: <a name="chapter-8"></a>

- Head to `database\seeders\DatabaseSeeder.php` and remove the comment from the line in `run()` function.
- This will allow you to create 10 fake users with Laravel Factory.

![Seeders php file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s9cw5zj4cxj72xfa4g8r.png)

- Open up the terminal in the main project directory to run your migration command and --seed the fake users to database.

`PS F:\Projects\dropdown-component> php artisan migrate --seed`

- You can test that everything is as expected to this point, head to `resources\views\welcome.blade.php` and clear it,
- Create new HTML boilerplate and in the body write the below code.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>dropdown</title>
</head>
<body>
    @foreach ($users as $user)
        <p>The name of the user is: {{ $user->name }}</p>
    @endforeach
</body>
</html>
```

- Open the terminal and hit the below code within the project main directory to serve and see your project in browser.

`PS F:\Projects\dropdown-component> php artisan serve`

- You should see now that Laravel is looping over the database User's table and giving us back the name for each user.

### 7- Install Tailwind CSS: <a name="chapter-9"></a>

- If you would like to install Tailwind CLI you can visit my article for a step by step guide on how to do that 🔗 [**CLICK HERE**](https://dev.to/moose_said/installing-tailwind-css-in-your-laravel-project-16f3)
- Or you can simply add the following line of code to import tailwind CDN in your project by following the steps in the documentation [**HERE**](https://tailwindcss.com/docs/installation/play-cdn)
- In my case, I will use tailwind CLI for better results.

### 8- Install Vue and it's dependencies: <a name="chapter-10"></a>

- Open the terminal in your project's main directory and run the below code to install Vue, Vue Router and Vue Loader.

`PS F:\Projects\dropdown-component> npm install vue@next vue-router@next vue-loader@next`

- I also prefer running `npm run watch` and leave it running in the backgroud while I'm working on my project.

`PS F:\Projects\dropdown-component> npm run watch`

- Head to `webpack.mix.js` file in your project's main directory and `.vue()` right before `postCss`.

```jsonc
mix.js("resources/js/app.js", "public/js")
    .vue()
    .postCss("resources/css/app.css", "public/css", [require("tailwindcss")]);
```

### 9- Prepare your blade file: <a name="chapter-11"></a>

- Head to the `welcome.blade.php` file and clear the body then I will add empty divs that will contain our Vue component with router-vue.
- Don't forget to add `id="app"`.

```html
<body>
    <main class="max-w-6xl mx-auto mt-6 lg:mt-20 space-y-6" 
                 id="app">

        <div class="max-w-xl mx-auto mt-10 text-center">
            <div class="space-y-2 lg:space-y-0 lg:space-x-4 mt-8" 
                        id="app">
                <div class="relative lg:inline-flex items-center 
                            bg-blue-100 rounded-xl">

                    <router-view />

                </div>
            </div>
        </div>

    </main>
</body>
```

### 10- Enable Vue and make component: <a name="chapter-12"></a>

- Head to `resources\js\app.js` and add the below code and save to enable Vue JS.

```jsonc
import { createApp } from "vue";

createApp({
    components: {},
}).mount("#app");
```

- Head to `resources\js` and create a subfolder called `components` and within that folder create `DropdownComponent.vue` file.
- Inside the file write Vue default setup and leave a 'hello world' for testing.

```Vue
<template>
    <h1 class="text-red-500 text-bold">Hello world</h1>
</template>

<script>
export default {};
</script>

<style></style>
```

- Now it's time to create our route to this component.
- Head to `resources\js` and create a subfolder called `router` and inside it create `index.js` file.
- Write the below code inside `index.js` file.
- In this code you're basically telling your project 

> Hi, I want to use Vue router and import this component whenever I'm in that path

```jsonc
import { createRouter, createWebHistory } from "vue-router";
import DropdownComponent from "../components/DropdownComponent";

const routes = [
    {
        path: "/",
        name: "home",
        component: DropdownComponent,
    },
];

export default createRouter({
    history: createWebHistory(),
    routes,
});
```

- Head back to `resources\js\app.js` and import your router and component.
- End result below.

```jsonc
import { createApp } from "vue";
import router from "./router";
import DropdownComponent from "./components/DropdownComponent";

createApp({
    components: {
        DropdownComponent,
    },
})
    .use(router)
    .mount("#app");
```

- Open up the terminal and stop your `npm run watch` if it's running and run it again to compile your files properly.
- Now if you refresh you broswer you should see your hello world.

### 11- Build the Drop-down: <a name="chapter-13"></a>

- Head back to `DropdownComponent.vue` and within the template you can start building your Dropdown.
- I create a container div which contains a button and a div. I want when I press on the button I can see list of links.
- I will add a `@click` to the button and conditionally show the div with links if some condition is true.

```Vue
<template>
    <div>
        <button
            @click="showUsers"
            class="flex max-h-52 w-full overflow-auto py-2 pl-3 pr-9 text-sm font-semibold lg:inline-flex lg:w-32"
        >
            Users
        </button>
        <div
            v-show="usersToggle"
            class="mt-1 w-full rounded-xl bg-blue-100 py-2"
        >
            <a href="#" class="block mt-1 w-full rounded-xl bg- 
                               blue-100 py-2">
                Testing
            </a>
        </div>
    </div>
</template>
```

- Now let's move to the script tags to import what we need and write down our logic using composition API.
- I will import ref and onMounted then create a usersToggle and set it to false and make the click on the button change it to true.

```Vue
<script>
import { ref, onMounted } from "vue";
export default {
    name: "home",
    setup() {
        const usersToggle = ref(false);

        const showUsers = () => {
            usersToggle.value = !usersToggle.value;
        };

        return { showUsers, usersToggle };
    },
};
</script>
```
- Now if you check your browser, whenever you click on the button it will open a drop-down list with the testing links and if you click it again it will close.

### 12- Vue JS 3 click outside: <a name="chapter-14"></a>

- Head to the following [**LINK**](https://www.npmjs.com/package/click-outside-vue3)and install npm click outside package for Vue3.
`PS F:\Projects\dropdown-component> npm install --save click-outside-vue3`
- Head to `app.js` and import it `import vClickOutside from "click-outside-vue3";` and don't forget to add `vClickOutside` just next to use router `.use(router, vClickOutside)`
- Head to `DropdownComponent.vue` and import it within the script tags `import vClickOutside from 'click-outside-vue3'`
- Add the directive as is says in the DOCs

```html
    directives: {
        clickOutside: vClickOutside.directive,
    },
```
- Then in the setup make sure to create your function that will make the usersToggle false again by clicking outside and return it.

```html
setup() {
        const usersToggle = ref(false);

        const showUsers = () => {
            usersToggle.value = !usersToggle.value;
        };

        const onClickOutside = (event) => {
            usersToggle.value = false;
        };

        return { showUsers, usersToggle, onClickOutside };
    },
```
- Within the template, add `v-click-outside="onClickOutside"` to the container div.
- Now if you test it on browser it works like a charm.

### 13- Loop over users in Database: <a name="chapter-15"></a>

- Create a new route to receive your Json data from database.

```php
Route::get('list', function () {
    return response()->json([
        'users' => \App\Models\User::all()
    ], Response::HTTP_OK);
});
```
- Head back to your component and adjust the anchor tag to loop over users array.

```html
            <a
                href="#"
                class="block mt-1 w-full rounded-xl bg-blue-100 
                       py-2"
                v-for="user in users"
                :key="user.id"
            >
                {{ user.name }}
            </a>
```
- In the setup, create empty array for users.

```html
        const users = ref([]);
```
- Then write the below code to say:

> Hey! Get my Json data as a response from this path, and change the users array value to whatever data in the response.
Not only this, I want this data as soon as my component is mounted and return it to me.

```html
        const getUsers = () => {
            axios.get("/list").then((response) => {
                users.value = response.data.users;
            });
        };

        onMounted(() => {
            getUsers();
        });

        return {
            showUsers,
            usersToggle,
            onClickOutside,
            getUsers,
            users,
        };
```
- Now, If you check your browser you will see your users names in a dynamic functional dropdown menu.

This is a final screen for my code in case you want to compare it to yours:
![Vue dropdown component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgkrrmw951gwvx467l9k.png)
 
Also you can find full code on Github: https://github.com/MooseSaeed/dropdown-component

### 14- Finishing: <a name="chapter-16"></a>

Congratulations you've created a complex Vue component with the latest release of everything 🎉🥳

Thank you so much for reading my article and I hope it was helpful for everyone.

If you have any questions, comments or feedback please leave them below or find me on [**Twitter**](https://twitter.com/Moose_Said) and DMs are open.