ふわっとメニュー
Nuxt3とTailwind CSSでふわっとフェードでメニューを表示する
Nuxt3でTailwind CSSとHeadless UIのDialogを使って、ハンバーガーメニューをクリックしたら、ふわっとフェードでメニューを表示しようとしたが、ページ遷移するとエラーを返し、うまくいかなかったので、Tailwind CSSだけで実装することに。案外簡単にできたので、メモ。
Tailwind CSSとHeadless UIのDialogで実装するもうまくいかない
下記サイトを参考に、docker上で認証を試していた時の話。認証系はうまくいったが、構成を改造していじっくっているうちに、エラーに遭遇しました。
基本はlayoutsを使い、headerには複数ページで使い回すcomponentsのheader.vueがあり、参考ページのようにHeadless UIのDialogを使っています。クリックすると、スライドやドロワーではなく、画面を覆うふわっとメニューにしたかったので、そのようにTailwind CSSを記述。しかし、メニューから遷移すると、Error: There are no focusable elements inside the <FocusTrap />がブラウザのコンソールに表示され、うまくいきません。Dialogなんで、1つのページでの制御で完結しているのかもと思いつつ、ページをまたがるやり方を探して色々あがいたのですが、やっぱりダメ。そこで、無理にHeadless UIを使わなくてもいいかと思い、Tailwind CSSだけで実装する道を模索しました。
クリックとCSSの連動で解決
最初はscriptに、addEventListnerとclassListを使ったjsを書いていましたが、onMountedで記述する際、ややこしくなったので、もっと楽できるやり方がありそうな気がしてcopilotに尋ねると、ズバリな解答をするではないですか。へぇ~、:classで値を渡してあげると変更できるのね。そうそう、コレコレと実装したのが以下の抜粋です。flagはfalseを渡したいものが複数あったので、こうなっていますが、ひっくり返るやつでも問題ありません。
<script lang="ts" setup>
import {
Bars3Icon,
XMarkIcon,
UserCircleIcon,
Cog6ToothIcon,
PencilIcon,
ExclamationCircleIcon,
HomeIcon,
} from '@heroicons/vue/24/outline';
const mobileMenuOpen = ref(false);
const menuBtnAction = (flag: boolean) => {
if (flag === true) {
mobileMenuOpen.value = true;
} else {
mobileMenuOpen.value = false;
}
};
</script>
<template>
<header class="inset-x-0 top-0 z-50">
<div>
<button
type="button"
class="naviWrap__open -m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
@click="menuBtnAction(true)"
>
<Bars3Icon class="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div
class="naviWrap fixed inset-0 px-6 lg:px-8 py-10 bg-white transition duration-200 ease-in-out"
:class="{
'-z-50 opacity-0': !mobileMenuOpen,
'z-50 opacity-100': mobileMenuOpen,
}"
>
<div>
<button
type="button"
class="menu__btn naviWrap__close -m-2.5 rounded-md p-2.5 text-gray-700"
@click="menuBtnAction(false)"
>
<XMarkIcon class="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div class="mt-6 flow-root">
<div class="-my-6 divide-y divide-dashed">
<NuxtLink
class="naviWrap__close flex items-center py-4"
@click="menuBtnAction(false)"
to="/dashboard/"
>
<HomeIcon class="w-6 h-6 mr-4 text-grey-500" />
ダッシュボード
</NuxtLink>
<NuxtLink
class="naviWrap__close flex items-center py-4"
@click="menuBtnAction(false)"
to="/dashboard/settings"
>
<PencilIcon class="w-6 h-6 mr-4 text-grey-500" />
記事作成
</NuxtLink>
<NuxtLink
class="naviWrap__close flex items-center py-4"
@click="menuBtnAction(false)"
to="/dashboard/settings"
>
<Cog6ToothIcon class="w-6 h-6 mr-4 text-grey-500" />
設定変更
</NuxtLink>
<NuxtLink
class="naviWrap__close flex items-center py-4"
@click="menuBtnAction(false)"
to="/dashboard/cancel"
>
<ExclamationCircleIcon class="w-6 h-6 mr-4 text-grey-500" />
退会
</NuxtLink>
<div class="border-b-1 border-dashed"></div>
</div>
</div>
</header>
</template>