Created
August 30, 2021 00:20
-
-
Save sumonst21/6ed04673e3554c509b8d5ec8fb57cfd3 to your computer and use it in GitHub Desktop.
Select Field with Search - AlpineJs + Tailwind
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="flex flex-col items-center"> | |
<div class="w-full md:w-1/2 flex flex-col items-center h-64"> | |
<div class="w-full px-4"> | |
<div x-data="selectConfigs()" x-init="fetchOptions()" class="flex flex-col items-center relative"> | |
<div class="w-full"> | |
<div @click.away="close()" class="my-2 p-1 bg-white flex border border-gray-200 rounded"> | |
<input | |
x-model="filter" | |
x-transition:leave="transition ease-in duration-100" | |
x-transition:leave-start="opacity-100" | |
x-transition:leave-end="opacity-0" | |
@mousedown="open()" | |
@keydown.enter.stop.prevent="selectOption()" | |
@keydown.arrow-up.prevent="focusPrevOption()" | |
@keydown.arrow-down.prevent="focusNextOption()" | |
class="p-1 px-2 appearance-none outline-none w-full text-gray-800"> | |
<div class="text-gray-300 w-8 py-1 pl-2 pr-1 border-l flex items-center border-gray-200"> | |
<button @click="toggle()" class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<polyline x-show="!isOpen()" points="18 15 12 20 6 15"></polyline> | |
<polyline x-show="isOpen()" points="18 15 12 9 6 15"></polyline> | |
</svg> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div x-show="isOpen()" class="absolute shadow bg-white top-100 z-40 w-full lef-0 rounded max-h-select overflow-y-auto svelte-5uyqqj"> | |
<div class="flex flex-col w-full"> | |
<template x-for="(option, index) in filteredOptions()" :key="index"> | |
<div @click="onOptionClick(index)" :class="classOption(option.login.uuid, index)" :aria-selected="focusedOptionIndex === index"> | |
<div class="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative hover:border-teal-100"> | |
<div class="w-6 flex flex-col items-center"> | |
<div class="flex relative w-5 h-5 bg-orange-500 justify-center items-center m-1 mr-2 w-4 h-4 mt-1 rounded-full "><img class="rounded-full" alt="A" x-bind:src="option.picture.thumbnail"> </div> | |
</div> | |
<div class="w-full items-center flex"> | |
<div class="mx-2 -mt-1"><span x-text="option.name.first + ' ' + option.name.last"></span> | |
<div class="text-xs truncate w-full normal-case font-normal -mt-1 text-gray-500" x-text="option.email"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function selectConfigs() { | |
return { | |
filter: '', | |
show: false, | |
selected: null, | |
focusedOptionIndex: null, | |
options: null, | |
close() { | |
this.show = false; | |
this.filter = this.selectedName(); | |
this.focusedOptionIndex = this.selected ? this.focusedOptionIndex : null; | |
}, | |
open() { | |
this.show = true; | |
this.filter = ''; | |
}, | |
toggle() { | |
if (this.show) { | |
this.close(); | |
} | |
else { | |
this.open() | |
} | |
}, | |
isOpen() { return this.show === true }, | |
selectedName() { return this.selected ? this.selected.name.first + ' ' + this.selected.name.last : this.filter; }, | |
classOption(id, index) { | |
const isSelected = this.selected ? (id == this.selected.login.uuid) : false; | |
const isFocused = (index == this.focusedOptionIndex); | |
return { | |
'cursor-pointer w-full border-gray-100 border-b hover:bg-blue-50': true, | |
'bg-blue-100': isSelected, | |
'bg-blue-50': isFocused | |
}; | |
}, | |
fetchOptions() { | |
fetch('https://randomuser.me/api/?results=5') | |
.then(response => response.json()) | |
.then(data => this.options = data); | |
}, | |
filteredOptions() { | |
return this.options | |
? this.options.results.filter(option => { | |
return (option.name.first.toLowerCase().indexOf(this.filter) > -1) | |
|| (option.name.last.toLowerCase().indexOf(this.filter) > -1) | |
|| (option.email.toLowerCase().indexOf(this.filter) > -1) | |
}) | |
: {} | |
}, | |
onOptionClick(index) { | |
this.focusedOptionIndex = index; | |
this.selectOption(); | |
}, | |
selectOption() { | |
if (!this.isOpen()) { | |
return; | |
} | |
this.focusedOptionIndex = this.focusedOptionIndex ?? 0; | |
const selected = this.filteredOptions()[this.focusedOptionIndex] | |
if (this.selected && this.selected.login.uuid == selected.login.uuid) { | |
this.filter = ''; | |
this.selected = null; | |
} | |
else { | |
this.selected = selected; | |
this.filter = this.selectedName(); | |
} | |
this.close(); | |
}, | |
focusPrevOption() { | |
if (!this.isOpen()) { | |
return; | |
} | |
const optionsNum = Object.keys(this.filteredOptions()).length - 1; | |
if (this.focusedOptionIndex > 0 && this.focusedOptionIndex <= optionsNum) { | |
this.focusedOptionIndex--; | |
} | |
else if (this.focusedOptionIndex == 0) { | |
this.focusedOptionIndex = optionsNum; | |
} | |
}, | |
focusNextOption() { | |
const optionsNum = Object.keys(this.filteredOptions()).length - 1; | |
if (!this.isOpen()) { | |
this.open(); | |
} | |
if (this.focusedOptionIndex == null || this.focusedOptionIndex == optionsNum) { | |
this.focusedOptionIndex = 0; | |
} | |
else if (this.focusedOptionIndex >= 0 && this.focusedOptionIndex < optionsNum) { | |
this.focusedOptionIndex++; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.8.1/alpine.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.top-100 {top: 100%} | |
.bottom-100 {bottom: 100%} | |
.max-h-select { | |
max-height: 300px; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.3/tailwind.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment