Improvements made:
Source: https://alpinejs.dev/component/dropdown
This component is subject to a product license.
<!-- Alpine Plugins -->
<script defer src="https://unpkg.com/@alpinejs/[email protected]/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<style>
[x-cloak] {
display: none !important;
}
</style>
<!--<h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1>-->
<div class="h-screen flex justify-center items-center">
<div class="flex justify-center">
<div x-data="{
open: false,
toggle() {
if (this.open) {
return this.close()
}
this.$refs.button.focus()
this.open = true
},
close(focusAfter) {
if (! this.open) return
this.open = false
focusAfter && focusAfter.focus()
}
}" x-on:keydown.escape.prevent.stop="close($refs.button)" x-on:focusin.window="! $refs.panel.contains($event.target) && close()" x-id="['dropdown-button']" class="relative">
<!-- Button -->
<button x-ref="button" x-on:click="toggle()" @keydown.down.prevent.stop="open = true, $focus.within($refs.panel).first()" @keydown.up.prevent.stop="open = true, $focus.within($refs.panel).last()" :aria-expanded="open" :aria-controls="$id('dropdown-button')" type="button" class="flex items-center gap-2 bg-white px-5 py-2.5 rounded-md shadow">
Options
<!-- Heroicon: chevron-down -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
<!-- Panel -->
<div x-ref="panel" @keydown.down.prevent.stop="$focus.next()" @keydown.up.prevent.stop="$focus.prev()" x-show="open" x-transition.origin.top.left x-on:click.outside="close($refs.button)" :id="$id('dropdown-button')" style="display: none;" class="absolute left-0 mt-2 w-40 rounded-md bg-white shadow-md">
<a href="#" class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
New Task
</a>
<a href="#" class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
Edit Task
</a>
<a href="#" class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
<span class="text-red-600">Delete Task</span>
</a>
</div>
</div>
</div>
</div>
<!-- This is the code I wrote using the video walk-through, pretty similar to above -->
<!--<div class="flex flex-col gap-4 justify-center items-center h-screen">-->
<!-- <div x-data="{-->
<!-- open: false,-->
<!-- toggle() {-->
<!-- this.open = this.open ? this.close() : true ;-->
<!-- },-->
<!-- close(focusAfter) {-->
<!-- this.open = false;-->
<!-- focusAfter && focusAfter.focus();-->
<!-- }-->
<!-- }"-->
<!-- @keydown.escape.prevent.stop="close($refs.button)"-->
<!-- @focusin.window="! $refs.panel.contains($event.target) && close()"-->
<!-- x-id="['dropdown-button']"-->
<!-- class="relative"-->
<!-- >-->
<!-- <!– Button –>-->
<!-- <button x-ref="button"-->
<!-- @click="toggle()"-->
<!-- :aria-expanded="open"-->
<!-- :aria-controls="$id('dropdown-button')"-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Actions</span>-->
<!-- <span aria-hidden="true">↓</span>-->
<!-- </button>-->
<!-- <!– Panel –>-->
<!-- <div x-ref="panel"-->
<!-- x-show="open"-->
<!-- x-transition.origin.top.left-->
<!-- @click.outside="close($refs.button)"-->
<!-- :id="$id('dropdown-button')"-->
<!-- x-cloak-->
<!-- class="absolute left-0 mt-2 bg-white border border-black"-->
<!-- >-->
<!-- <div>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- New Task-->
<!-- </a>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- Edit Task-->
<!-- </a>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- <span class="text-red-600 whitespace-nowrap">Delete Task</span>-->
<!-- </a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="flex gap-x-2">-->
<!-- <!– Button –>-->
<!-- <button-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Other Button</span>-->
<!-- </button>-->
<!-- <!– Button –>-->
<!-- <button-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Another Button</span>-->
<!-- </button>-->
<!-- </div>-->
<!--</div>-->
<!-- Alpine Plugins -->
<script defer src="https://unpkg.com/@alpinejs/[email protected]/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<style>
[x-cloak] {
display: none !important;
}
</style>
<!--<h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1>-->
<div class="h-screen flex justify-center items-center">
<div class="flex justify-center">
<div
x-data="{
open: false,
toggle() {
if (this.open) {
return this.close()
}
this.$refs.button.focus()
this.open = true
},
close(focusAfter) {
if (! this.open) return
this.open = false
focusAfter && focusAfter.focus()
}
}"
x-on:keydown.escape.prevent.stop="close($refs.button)"
x-on:focusin.window="! $refs.panel.contains($event.target) && close()"
x-id="['dropdown-button']"
class="relative"
>
<!-- Button -->
<button
x-ref="button"
x-on:click="toggle()"
@keydown.down.prevent.stop="open = true, $focus.within($refs.panel).first()"
@keydown.up.prevent.stop="open = true, $focus.within($refs.panel).last()"
:aria-expanded="open"
:aria-controls="$id('dropdown-button')"
type="button"
class="flex items-center gap-2 bg-white px-5 py-2.5 rounded-md shadow"
>
Options
<!-- Heroicon: chevron-down -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"/>
</svg>
</button>
<!-- Panel -->
<div
x-ref="panel"
@keydown.down.prevent.stop="$focus.next()"
@keydown.up.prevent.stop="$focus.prev()"
x-show="open"
x-transition.origin.top.left
x-on:click.outside="close($refs.button)"
:id="$id('dropdown-button')"
style="display: none;"
class="absolute left-0 mt-2 w-40 rounded-md bg-white shadow-md"
>
<a href="#"
class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
New Task
</a>
<a href="#"
class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
Edit Task
</a>
<a href="#"
class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">
<span class="text-red-600">Delete Task</span>
</a>
</div>
</div>
</div>
</div>
<!-- This is the code I wrote using the video walk-through, pretty similar to above -->
<!--<div class="flex flex-col gap-4 justify-center items-center h-screen">-->
<!-- <div x-data="{-->
<!-- open: false,-->
<!-- toggle() {-->
<!-- this.open = this.open ? this.close() : true ;-->
<!-- },-->
<!-- close(focusAfter) {-->
<!-- this.open = false;-->
<!-- focusAfter && focusAfter.focus();-->
<!-- }-->
<!-- }"-->
<!-- @keydown.escape.prevent.stop="close($refs.button)"-->
<!-- @focusin.window="! $refs.panel.contains($event.target) && close()"-->
<!-- x-id="['dropdown-button']"-->
<!-- class="relative"-->
<!-- >-->
<!-- <!– Button –>-->
<!-- <button x-ref="button"-->
<!-- @click="toggle()"-->
<!-- :aria-expanded="open"-->
<!-- :aria-controls="$id('dropdown-button')"-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Actions</span>-->
<!-- <span aria-hidden="true">↓</span>-->
<!-- </button>-->
<!-- <!– Panel –>-->
<!-- <div x-ref="panel"-->
<!-- x-show="open"-->
<!-- x-transition.origin.top.left-->
<!-- @click.outside="close($refs.button)"-->
<!-- :id="$id('dropdown-button')"-->
<!-- x-cloak-->
<!-- class="absolute left-0 mt-2 bg-white border border-black"-->
<!-- >-->
<!-- <div>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- New Task-->
<!-- </a>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- Edit Task-->
<!-- </a>-->
<!-- <a href="#"-->
<!-- class="flex items-center gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm hover:bg-gray-50 disabled:text-gray-500">-->
<!-- <span class="text-red-600 whitespace-nowrap">Delete Task</span>-->
<!-- </a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="flex gap-x-2">-->
<!-- <!– Button –>-->
<!-- <button-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Other Button</span>-->
<!-- </button>-->
<!-- <!– Button –>-->
<!-- <button-->
<!-- type="button"-->
<!-- class="border border-black px-4 py-2 focus:outline-none focus:ring-4 focus:ring-aqua-400"-->
<!-- >-->
<!-- <span>Another Button</span>-->
<!-- </button>-->
<!-- </div>-->
<!--</div>-->
/* No context defined. */