Using Classnames with Alpine for a dropdown
by philw_
HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.4.5/tailwind.min.css">
<script src="https://cdn.jsdelivr.net/gh/ctidigital/outline.js@1.3.0/outline.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ally.js@1.4.1/ally.min.js"></script>
<!-- Classnames isn't needed in Alpine v2 but might be in v3 -->
<script
src="https://cdn.jsdelivr.net/npm/classnames@2.2.6/index.js"
integrity="sha256-rrq9qHuIVReH5epxJgE6YObA8I1zK7lcx5ZUBZrwMXE="
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/alpinejs@2.3.3/dist/alpine.js"
integrity="sha256-YMtt6o4gwAMeWbjhX1r2n/ZgaCCA7BEKCRsLVN+qeDA="
crossorigin="anonymous"
></script>
<main class="space-y-8">
<div
x-data="{
open: false,
tabConstraint: null
}"
class="relative dropdown max-w-sm"
x-on:keydown.escape="open = false"
x-init="
// In real life I'd put this in a .js file to benefit from
// Prettier, linting, minifying etc, but it's _possible_ to
// do it all inside your markup.
$watch('open', (open) => {
$dispatch('toggle-overlay', { state: open });
$nextTick(() => {
tabConstraint = open
? ally.maintain.tabFocus({ context: $el })
: tabConstraint.disengage();
if (open) { $refs.firstLink.focus(); }
});
});
"
>
<button
id="dropdown-button"
@click="open = true"
class="w-full flex font-bold p-5"
:class="classNames(
{
'bg-red-500 rounded-t-lg relative z-10': open,
'bg-gray-300 hover:bg-gray-400 focus:bg-gray-400 rounded-lg': !open
}
)"
aria-haspopup="true"
:aria-expanded="open"
>
<div class="flex-grow">
<span x-text="!open ? 'Open' : 'Hide'">Open</span> dropdown
</div>
<div class="w-6">
<div x-show="!open" data-feather="menu"></div>
<div x-show="open" data-feather="x"></div>
</div>
...
SCSS
[x-cloak] { display: none; }
p {
a {
text-decoration: underline;
&:hover,
&:focus {
color: #2b6cb0;
}
}
}
JavaScript
// No JS here!