TailwindUIのJavascriptが提供されてない件
概要
ずっとSASSとBootstrapでやってましたが遅ればせながらTailwindを触ってみました。コンセプトはなかなか気に入ったのですが、公式のTailwindUIは、ReactかVue以外で使う時はJavascriptは自分で書かないとダメみたいです。
TailwindUIのDropdwonのJSを書いてみたので置いておきます。
コード
document.addEventListener('DOMContentLoaded', () => {
const toShowClasses = ['opacity-100', 'scale-100'];
const toHideClasses = ['opacity-0', 'scale-95'];
const dropdowns = document.querySelectorAll('.dropdown');
dropdowns.forEach(dropdown => {
const trigger = dropdown.querySelector('.dropdown-trigger');
const menu = dropdown.querySelector('.dropdown-menu');
if (trigger === null || menu === null) return;
menu.classList.add(...toHideClasses, 'transition', 'duration-100', 'ease-out');
menu.addEventListener('transitionend', () => {
if (toHideClasses.every(c => menu.classList.contains(c))) {
menu.classList.add('hidden');
}
});
trigger.addEventListener('click', () => {
if (menu.classList.contains('hidden')) {
menu.classList.remove('hidden');
setTimeout(() => {
menu.classList.remove(...toHideClasses);
menu.classList.add(...toShowClasses);
}, 0);
} else {
menu.classList.remove(...toShowClasses);
menu.classList.add(...toHideClasses);
}
});
});
document.addEventListener('click', event => {
if (event.target) {
const target = event.target as HTMLElement;
if (target.closest('.dropdown-menu')) {
return;
}
}
dropdowns.forEach(dropdown => {
const menu = dropdown.querySelector('.dropdown-menu');
if (menu === null) return;
menu.classList.remove(...toShowClasses);
menu.classList.add(...toHideClasses);
});
});
});
<div class="dropdown relative inline-block text-left">
<div>
<button
type="button"
class="dropdown-trigger inline-flex w-full justify-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
id="menu-button"
aria-expanded="true"
aria-haspopup="true"
>
Options
<svg class="-mr-1 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
<div
class="dropdown-menu absolute right-0 z-10 mt-2 hidden w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="menu-button"
tabindex="-1"
>
<div class="py-1" role="none">
<!-- Active: "bg-gray-100 text-gray-900", Not Active: "text-gray-700" -->
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="menu-item-0"
>Account settings</a
>
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="menu-item-1"
>Support</a
>
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="menu-item-2"
>License</a
>
<form method="POST" action="#" role="none">
<button
type="submit"
class="block w-full px-4 py-2 text-left text-sm text-gray-700"
role="menuitem"
tabindex="-1"
id="menu-item-3"
>
Sign out
</button>
</form>
</div>
</div>
</div>
解説
Javascriptのトリガーとしてラッパーとボタンとメニューにそれぞれdropdown
、dropdown-trigger
、dropdown-menu
のクラスを付与しました。
ドキュメントを読むとHTMLに付与するクラスのヒントが書いてあります。
<!--
Dropdown menu, show/hide based on menu state.
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
-->
これをonClickでつけたり外したりしてるだけですね。メニューはdisplay:none
にしないと他の要素のクリックを阻害すると思うのでhidden
もつけたり外したりしてますが、hidden
を外してすぐクラスを付与してもtransition
のアニメーションが動かないようです。なのでsetTimeout
で処理を後ろに回してます。
ページロード時にメニューが表示されないようにHTML側にもhiddenをつけてます。これをつけないと一瞬見えます。
ドキュメントクリックで閉じる挙動が一般的だと思うのでそうしました。
このドロップダウンは左寄せ(ボタンと右側のツラが揃った状態)で表示されますが、right-0 origin-top-right
を、それぞれleft
に変えてやると右寄せに変わります。
注意点
2023/11/17に追記
Tailwind慣れてる人には当たり前かもしれないけど、ハマったので追記。tailwindは使用してないCSSは読み込みません。使用してるかどうか検索するファイルの指定はtailwind.config.js
のcontent
に指定します。contentに指定を忘れて、JSやTSにクラス名を記載してもしそれがHTML無いと読み込まれず動きません。動いていたも(何故動いてたのか謎だが)のがいつも間にか動かなくなってハマりました。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['app/views/**/*.html.erb', 'app/frontend/**/*.js', , 'app/frontend/**/*.ts'],
plugins: [require('@tailwindcss/typography'), require('@tailwindcss/forms')],
};
感想
299ドルも取ってJSは自分で書けって、それは無いだろ、って気はしますね。まあ、JSが必要なのはDropdownとModalくらいらしいですが。しかも、関係ないけど299ドルって今45,000円を超えるんですね。クレジットカードだと少し高めに来るので5万近いのかな?円安どうにかしろ!政府。
他のComponentライブラリも触ってみましたがボタンにインタラクションがなかったり、チェックボックスのテキストがなぜか左側だったり、デザインが好みじゃなかったり・・・Sailboat UIがいい感じでライセンスもMITですが、Alpinejsを使ってるのがあまり好きじゃ無いのとComponentの数も頼りない感じです。
あと、ピュアなtailwindではなくbtn
とかpanel
みたいに独自クラスにまとまってると依存度が高そうで微妙な感じもします。
もう一つ無料でおすすめはこれですかね。ただ、こちらもピュアなHTMLの場合JSは自分で実装しないとダメそうですね(たぶん)。
細かい説明は端折りますがいくつか貼っときますね。
おすすめのComponentライブラリがあったらコメントで教えていただけると嬉しいです。
Discussion