Published on

6 Easy Ways To Build A Multi Select Alpine Js With Tailwind CSS Without Even Thinking About It

Multi select alpine js

As a FrontEnd technology blogger, I'm always on the lookout for ways to make my development process faster and more efficient. One tool that has been a game-changer for me is Tailwind CSS. It's a utility-first CSS framework that makes it easy to create custom designs without writing a lot of custom CSS. In this article, I'll show you how to use Tailwind CSS to build a multi-select Alpine JS UI component in just a few easy steps.

What is Tailwind CSS?

Tailwind CSS is a utility-first CSS framework that allows you to create custom designs without writing a lot of custom CSS. It's based on a set of pre-defined CSS classes that you can use to style your HTML elements. Tailwind CSS is highly customizable, and you can easily change the default styles to match your brand or design requirements.

The description of Multi select alpine js ui component

A multi-select Alpine JS UI component is a user interface element that allows users to select multiple options from a list. It's a useful component for forms, surveys, and other applications that require users to select multiple options. The component is built using Alpine JS, a lightweight JavaScript framework that allows you to add interactivity to your web pages without writing a lot of code.

Why use Tailwind CSS to create a Multi select alpine js ui component?

Tailwind CSS makes it easy to create custom designs without writing a lot of custom CSS. You can use the pre-defined CSS classes to style your HTML elements, which saves you a lot of time and effort. Additionally, Tailwind CSS is highly customizable, so you can easily change the default styles to match your design requirements.

The preview of Multi select alpine js ui component.

To give you an idea of what the multi-select Alpine JS UI component looks like, here's a preview:

Free download of the Multi select alpine js's source code

The source code of Multi select alpine js ui component.

Here's the source code for the multi-select Alpine JS UI component:

<!-- This is an example component -->
  <div>
      <script type="module" src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js"></script>
      <script nomodule src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine-ie11.min.js" defer></script>

      <style>
          [x-cloak] {
              display: none;
          }
      </style>
      <select x-cloak id="select">
          <option value="1">Option 2</option>
          <option value="2">Option 3</option>
          <option value="3">Option 4</option>
          <option value="4">Option 5</option>
      </select>

 <div x-data="dropdown()" x-init="loadOptions()" class="w-full md:w-1/2 flex flex-col items-center h-64 mx-auto">
    <form>
        <input name="values" type="hidden" x-bind:value="selectedValues()">
        <div class="inline-block relative w-64">
            <div class="flex flex-col items-center relative">
                <div x-on:click="open" class="w-full  svelte-1l8159u">
                    <div class="my-2 p-1 flex border border-gray-200 bg-white rounded svelte-1l8159u">
                        <div class="flex flex-auto flex-wrap">
                            <template x-for="(option,index) in selected" :key="options[option].value">
                                <div
                                    class="flex justify-center items-center m-1 font-medium py-1 px-2 bg-white rounded-full text-teal-700 bg-teal-100 border border-teal-300 ">
                                    <div class="text-xs font-normal leading-none max-w-full flex-initial x-model="
                                        options[option]" x-text="options[option].text"></div>
                                    <div class="flex flex-auto flex-row-reverse">
                                        <div x-on:click="remove(index,option)">
                                            <svg class="fill-current h-6 w-6 " role="button" viewBox="0 0 20 20">
                                                <path d="M14.348,14.849c-0.469,0.469-1.229,0.469-1.697,0L10,11.819l-2.651,3.029c-0.469,0.469-1.229,0.469-1.697,0
                                           c-0.469-0.469-0.469-1.229,0-1.697l2.758-3.15L5.651,6.849c-0.469-0.469-0.469-1.228,0-1.697s1.228-0.469,1.697,0L10,8.183
                                           l2.651-3.031c0.469-0.469,1.228-0.469,1.697,0s0.469,1.229,0,1.697l-2.758,3.152l2.758,3.15
                                           C14.817,13.62,14.817,14.38,14.348,14.849z" />
                                            </svg>

                                        </div>
                                    </div>
                                </div>
                            </template>
                            <div x-show="selected.length    == 0" class="flex-1">
                                <input placeholder="Select a option"
                                    class="bg-transparent p-1 px-2 appearance-none outline-none h-full w-full text-gray-800"
                                    x-bind:value="selectedValues()"
                                >
                            </div>
                        </div>
                        <div
                            class="text-gray-300 w-8 py-1 pl-2 pr-1 border-l flex items-center border-gray-200 svelte-1l8159u">

                            <button type="button" x-show="isOpen() === true" x-on:click="open"
                                class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
                                <svg version="1.1" class="fill-current h-4 w-4" viewBox="0 0 20 20">
                                    <path d="M17.418,6.109c0.272-0.268,0.709-0.268,0.979,0s0.271,0.701,0,0.969l-7.908,7.83
	c-0.27,0.268-0.707,0.268-0.979,0l-7.908-7.83c-0.27-0.268-0.27-0.701,0-0.969c0.271-0.268,0.709-0.268,0.979,0L10,13.25
	L17.418,6.109z" />
                                </svg>

                            </button>
                            <button type="button" x-show="isOpen() === false" @click="close"
                                class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
                                <svg class="fill-current h-4 w-4" viewBox="0 0 20 20">
                                    <path d="M2.582,13.891c-0.272,0.268-0.709,0.268-0.979,0s-0.271-0.701,0-0.969l7.908-7.83
	c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271,0.268-0.709,0.268-0.978,0L10,6.75L2.582,13.891z
	" />
                                </svg>

                            </button>
                        </div>
                    </div>
                </div>
                <div class="w-full px-4">
                    <div x-show.transition.origin.top="isOpen()"
                        class="absolute shadow top-100 bg-white z-40 w-full lef-0 rounded max-h-select overflow-y-auto svelte-5uyqqj"
                        x-on:click.away="close">
                        <div class="flex flex-col w-full">
                            <template x-for="(option,index) in options" :key="option">
                                <div>
                                    <div class="cursor-pointer w-full border-gray-100 rounded-t border-b hover:bg-teal-100"
                                        @click="select(index,$event)">
                                        <div x-bind:class="option.selected ? 'border-teal-600' : ''"
                                            class="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative">
                                            <div class="w-full items-center flex">
                                                <div class="mx-2 leading-6" x-model="option" x-text="option.text"></div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </template>
                        </div>
                    </div>
                </div>
            </div>
			<!-- on tailwind components page will no work  -->
            <button disabled class="flex-shrink-0 bg-teal-500 hover:bg-teal-700 border-teal-500 hover:border-teal-700 text-sm border-4 text-white py-1 px-2 rounded" type="submit">Test</button>
        </form>
        </div>
        

        <script>
            function dropdown() {
                return {
                    options: [],
                    selected: [],
                    show: false,
                    open() { this.show = true },
                    close() { this.show = false },
                    isOpen() { return this.show === true },
                    select(index, event) {

                        if (!this.options[index].selected) {

                            this.options[index].selected = true;
                            this.options[index].element = event.target;
                            this.selected.push(index);

                        } else {
                            this.selected.splice(this.selected.lastIndexOf(index), 1);
                            this.options[index].selected = false
                        }
                    },
                    remove(index, option) {
                        this.options[option].selected = false;
                        this.selected.splice(index, 1);


                    },
                    loadOptions() {
                        const options = document.getElementById('select').options;
                        for (let i = 0; i < options.length; i++) {
                            this.options.push({
                                value: options[i].value,
                                text: options[i].innerText,
                                selected: options[i].getAttribute('selected') != null ? options[i].getAttribute('selected') : false
                            });
                        }


                    },
                    selectedValues(){
                        return this.selected.map((option)=>{
                            return this.options[option].value;
                        })
                    }
                }
            }
        </script>
  </div>

How to create a Multi select alpine js with Tailwind CSS?

Now that you know what the multi-select Alpine JS UI component is and why you should use Tailwind CSS to create it, let's get started with the tutorial. Here are the six easy steps to create a multi-select Alpine JS UI component with Tailwind CSS:

Step 1: Set up your HTML

The first step is to set up your HTML. Here's an example:

<div x-data="{ open: false, selected: [] }" class="relative">
  <button @click="open = !open" class="w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300">
    <span x-show="selected.length == 0">Select an option</span>
    <template x-for="(option, index) in selected" :key="index">
      <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-sm font-medium bg-blue-100 text-blue-800 mr-2">
        {{ option }}
        <button type="button" @click="selected.splice(index, 1)" class="flex-shrink-0 ml-1.5 inline-flex text-blue-500 focus:outline-none focus:text-blue-700">
          <svg class="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8">
            <path stroke-linecap="round" d="M1 1l6 6M1 7L7 1"></path>
          </svg>
        </button>
      </span>
    </template>
    <svg class="absolute top-0 right-0 w-5 h-5 mt-2 mr-3 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
      <path fill-rule="evenodd" d="M6.293 7.293a1 1 0 011.414 0L10 9.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd"></path>
    </svg>
  </button>
  <div x-show="open" @click.away="open = false" class="absolute z-10 w-full mt-2 rounded-md bg-white shadow-lg">
    <ul class="list-none">
      <li @click="selected.includes('Option 1') ? selected.splice(selected.indexOf('Option 1'), 1) : selected.push('Option 1')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 1</li>
      <li @click="selected.includes('Option 2') ? selected.splice(selected.indexOf('Option 2'), 1) : selected.push('Option 2')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 2</li>
      <li @click="selected.includes('Option 3') ? selected.splice(selected.indexOf('Option 3'), 1) : selected.push('Option 3')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 3</li>
      <li @click="selected.includes('Option 4') ? selected.splice(selected.indexOf('Option 4'), 1) : selected.push('Option 4')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 4</li>
      <li @click="selected.includes('Option 5') ? selected.splice(selected.indexOf('Option 5'), 1) : selected.push('Option 5')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 5</li>
    </ul>
  </div>
</div>

Step 2: Add the necessary CSS classes

Next, you need to add the necessary CSS classes to your HTML elements. Here's an example:

<div x-data="{ open: false, selected: [] }" class="relative">
  <button @click="open = !open" class="w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300">
    <span x-show="selected.length == 0">Select an option</span>
    <template x-for="(option, index) in selected" :key="index">
      <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-sm font-medium bg-blue-100 text-blue-800 mr-2">
        {{ option }}
        <button type="button" @click="selected.splice(index, 1)" class="flex-shrink-0 ml-1.5 inline-flex text-blue-500 focus:outline-none focus:text-blue-700">
          <svg class="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8">
            <path stroke-linecap="round" d="M1 1l6 6M1 7L7 1"></path>
          </svg>
        </button>
      </span>
    </template>
    <svg class="absolute top-0 right-0 w-5 h-5 mt-2 mr-3 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
      <path fill-rule="evenodd" d="M6.293 7.293a1 1 0 011.414 0L10 9.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd"></path>
    </svg>
  </button>
  <div x-show="open" @click.away="open = false" class="absolute z-10 w-full mt-2 rounded-md bg-white shadow-lg">
    <ul class="list-none">
      <li @click="selected.includes('Option 1') ? selected.splice(selected.indexOf('Option 1'), 1) : selected.push('Option 1')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 1</li>
      <li @click="selected.includes('Option 2') ? selected.splice(selected.indexOf('Option 2'), 1) : selected.push('Option 2')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 2</li>
      <li @click="selected.includes('Option 3') ? selected.splice(selected.indexOf('Option 3'), 1) : selected.push('Option 3')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 3</li>
      <li @click="selected.includes('Option 4') ? selected.splice(selected.indexOf('Option 4'), 1) : selected.push('Option 4')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 4</li>
      <li @click="selected.includes('Option 5') ? selected.splice(selected.indexOf('Option 5'), 1) : selected.push('Option 5')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 5</li>
    </ul>
  </div>
</div>

Step 3: Add the Alpine JS script

Next, you need to add the Alpine JS script to your HTML. Here's an example:

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3"></script>

Step 4: Initialize the Alpine JS component

Next, you need to initialize the Alpine JS component. Here's an example:

<div x-data="{ open: false, selected: [] }" class="relative">
  ...
</div>

Step 5: Add the click event handlers

Next, you need to add the click event handlers to your HTML elements. Here's an example:

<div x-data="{ open: false, selected: [] }" class="relative">
  <button @click="open = !open" class="w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300">
    ...
  </button>
  <div x-show="open" @click.away="open = false" class="absolute z-10 w-full mt-2 rounded-md bg-white shadow-lg">
    <ul class="list-none">
      <li @click="selected.includes('Option 1') ? selected.splice(selected.indexOf('Option 1'), 1) : selected.push('Option 1')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 1</li>
      <li @click="selected.includes('Option 2') ? selected.splice(selected.indexOf('Option 2'), 1) : selected.push('Option 2')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 2</li>
      <li @click="selected.includes('Option 3') ? selected.splice(selected.indexOf('Option 3'), 1) : selected.push('Option 3')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 3</li>
      <li @click="selected.includes('Option 4') ? selected.splice(selected.indexOf('Option 4'), 1) : selected.push('Option 4')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 4</li>
      <li @click="selected.includes('Option 5') ? selected.splice(selected.indexOf('Option 5'), 1) : selected.push('Option 5')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 5</li>
    </ul>
  </div>
</div>

Step 6: Add the necessary styles

Finally, you need to add the necessary styles to your HTML elements. Here's an example:

<div x-data="{ open: false, selected: [] }" class="relative">
  <button @click="open = !open" class="w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300">
    ...
  </button>
  <div x-show="open" @click.away="open = false" class="absolute z-10 w-full mt-2 rounded-md bg-white shadow-lg">
    <ul class="list-none">
      <li @click="selected.includes('Option 1') ? selected.splice(selected.indexOf('Option 1'), 1) : selected.push('Option 1')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 1</li>
      <li @click="selected.includes('Option 2') ? selected.splice(selected.indexOf('Option 2'), 1) : selected.push('Option 2')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 2</li>
      <li @click="selected.includes('Option 3') ? selected.splice(selected.indexOf('Option 3'), 1) : selected.push('Option 3')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 3</li>
      <li @click="selected.includes('Option 4') ? selected.splice(selected.indexOf('Option 4'), 1) : selected.push('Option 4')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 4</li>
      <li @click="selected.includes('Option 5') ? selected.splice(selected.indexOf('Option 5'), 1) : selected.push('Option 5')" class="px-4 py-2 hover:bg-gray-100 cursor-pointer">Option 5</li>
    </ul>
  </div>
</div>

Conclusion

In this article, we've shown you how to use Tailwind CSS to create a multi-select Alpine JS UI component in just a few easy steps. With Tailwind CSS, you can create custom designs without writing a lot of custom CSS, which saves you a lot of time and effort. Additionally, Alpine JS is a lightweight JavaScript framework that allows you to add interactivity to your web pages without writing a lot of code. Together, Tailwind CSS and Alpine JS make it easy to create beautiful and functional user interfaces with minimal effort.