はじめに
UIライブラリとして最近話題なのはshadcnです。これは擬銃的にはRadix UIのスライル無しなコンポーネントにTailwind CSSでスタイリングをしたものです。
ただしRadix UIはReactに完全に依存します。Reactが無い環境ではい使用できず、Vue、SvelteやただのHTML/JSで使用することができません。もちろんHotwireで使用することもできません。同じようにスタイル無しのコンポーネントを提供するHeadlessUIもReactもしくはVueを必要としており、最新のUIコンポーネントライブラリはReact等が前提という流れになっていました。
そこに一石を投じるのが、Tailwind Labsが7月25日に公開したTailwind Elementsです。Tailwind LabsはHeadless UIも作ったのですが、今回のTailwind ElementsはHeadless UIをReact無しのVanilla JavaScriptで作成したものと言えそうです。React/Vueに依存しませんので、Svelte、ただのHTML/JS、そしてもちろんHotwireでも使用できます。
これはUIライブラリの風向きをも変える可能性がある、非常に面白い技術だと思いますので、ここで紹介したいと思います。
なぜ切望されていたか
Reactの大きな強みの一つは、UIライブラリの充実です。
インタラクティブ性だけならSvelteでもHotwireでも、Reactと肩を並べるもしくは凌駕するものが作れます。またReactが可能にするCSS-in-JSやCSS moduleも、最近ではTailwind CSSに押され、またReact Server Componentsとの相性の悪さから第一選択肢ではなくなりました。そんな中でも、Reactは依然としてUIライブラリエコシステムの充実で他のものを寄せ付けませんでした。ある意味、これがReactの砦です。
特にHotwireのコミュニティではプロ級のUIライブラリを作る努力がされてきていましたが、これといったものはなかなか生まれませんでした。
そこでTailwind Labsから出てきたTailwind Elementsは、Tailwind CSSの後押しもあり、大いに注目できるものだと思います。Headless UIを作ったのと同じ人たちですので、a11yを含めてプロ級のもののはずです。これがReactでもVueでもなく、Vanilla JSとHTMLでできたことのインパクトは大きいと思います。
実際に試してみた
Tailwind PlusはTailwind Labsが提供する有料のサービスで、個人であれば$299、チーム(25名まで)であれば$979のサービスです。自分が作った製品の中で使用するのであれば、使用に制限はありません。
今回はNext.jsを使って、複数のフロントエンド環境で試してみました。試したのは以下のものです。Tailwind Labsが作ったものですので当然のように完成度が高く、Tailwind ElementsとHeadless UIの間でUI/UX的に差異が気になることはありません。
- ただのHTML (plain HTML)でTailwind Elementsを使用したもの:
デモ: https://tailwind-elements-demo.vercel.app/plain.html
ソースコード: https://github.com/naofumi/tailwind_elements_demo/blob/main/public/plain.html - Next.jsのServer Components (RSC)でTailwind Elementsを使用したもの:
デモ: https://tailwind-elements-demo.vercel.app/server_component
ソースコード: https://github.com/naofumi/tailwind_elements_demo/blob/main/app/server_component/page.tsx - Reactの従来手法 – useEffectを使ったデータ読み込みでTailwind Elementsを使用したもの:
デモ: https://tailwind-elements-demo.vercel.app/use_effect
ソースコード: https://github.com/naofumi/tailwind_elements_demo/blob/main/app/use_effect/page.tsx - HeadlessUIを使ったもの (Tailwind Elementsとの比較として):
デモ: https://tailwind-elements-demo.vercel.app/headless_ui
ソースコード: https://github.com/naofumi/tailwind_elements_demo/blob/main/app/headless_ui/page.tsx
ただのHTML (plain HTML)で使用した時の感想
-
紹介記事でも記載されているように、Tailwind Elementsを使うには
タグを一つ用意するだけで十分です。紹介されているようにCDNから読み込んでも良いし、NPMからインストールすることもできます。私が作成したデモだとここのコードになります。
- また紹介記事で記載されているように、使用するのは
や
などの非常に簡単なcustom elementです。 - キーボード操作やfocusなどのa11yは対応されています(私自身の知識不足のため、十分かどうかは判定できません)
Server Componentsで使用した時の感想
Next.jsのApp Routerなどで使用されるServer Components (RSC)の大きな特徴はhydrationを行わないことです。つまりページはJSXで記載されているのですが、Reactのインタラクティビティがありません。JavaScriptをオフにしたときと同じような操作しかできませんし、それ以上のことをやりたければ “use client”を設定してClient Componentを使うしかありません。
しかしTailwind ElementsはRSCでも使えます。React由来のJavaScriptは無くても、Tailwind ElementsのJavaScriptを使えば、デモで用意したcomboboxが使用できます。
タグでTailwind Elementsを読み込み、あとはcustom elementsを使用するだけです。plain HTMLを使っている場合となんら変わりはありません。
export default function RscPage() {
const userList = getUserList()
return (
>
Script src="https://cdn.jsdelivr.net/npm/@tailwindplus/elements@1" type="module">/Script>
...
label htmlFor="autocomplete" className="block text-sm/6 font-medium text-gray-900">Assigned to/label>
el-autocomplete className="relative mt-2 block">
input id="autocomplete" type="text"
className="block w-full rounded-md bg-white py-1.5 pr-12 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"/>
button type="button" className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2">
svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true"
className="size-5 text-gray-400">
path
d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z"
clipRule="evenodd" fillRule="evenodd"/>
/svg>
/button>
el-options anchor="bottom end" popover
className="max-h-60 w-(--input-width) overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 [--anchor-gap:--spacing(1)] sm:text-sm">
{userList.map((user) => (
el-option value={user} key={user}
className="block truncate px-3 py-2 text-gray-900 select-none aria-selected:bg-indigo-600 aria-selected:text-white">
{user}
/el-option>
))}
/el-options>
/el-autocomplete>
/main>
/>
)
}
HeadlessUIのコードと比較して
HeadlessUIを使った時のコードも用意しました。(デモ、ソースコード)
HeadlessUI版はフィルタのロジックをカスタムで実装しているほか、実装周りのコードが多くなっています。Tailwind Elements版よりは低レベルのコードが多く、カスタマイズ性は高いものの、開発者の負担は多めな気がします。Tailwind Elementsの方が例えばShadcnに近い印象を受けます。
またHeadlessUIはRSCと組み合わせた場合に気をつけなければならない点があります。HeadlessUIのコンポーネントは全てClient Componentになりますので、top階層のコンポーネントでは "use client"
を記述しなければなりません。
もちろん上手にServer ComponentとClient Componentを使い分けられるのであれば問題はないのですが、Tailwind Elementsならそもそも考えなくても良いことなので、わかりやすさではTailwind Elementsの方が優れているように思います。
最後に
私はHotwireを推していますので、Hotwireと親和性の高いUIライブラリ技術が増えることは大歓迎です。しかもTailwind ElementsはTailwind Labsから出ていますので、サポート面でも安心できますし、完成度の高さも期待できます。有料とはいえ、かなり利用が増えるのではないかと予想されます。
今までHotwireにはUIライブラリが欠けていましたが、Tailwind Elementsでかなり取り返せそうに感じます。これはReact以外のフロントエンドライブラリ全般にとっても言えることだと思います。
またUIライブラリは栄枯盛衰が激しく、頻繁に入れ替わります。Shadcnで使われているRadixUIのサポートも懸念があり、これも早期に新しいものに取って代わられる可能性を感じます。次世代のものはTailwind Elementsのように、Reactではなくweb componentsのcustom elementsを活用したものになりそうが予感があります。
MosaicやNetscapeなどの初代のウェブブラウザを作り、ベンチャーキャピタリストとして有名なMarc Andreessen氏は、「世の中でお金を作る方法は2つしかない。一つはバンドルすることだ。もう一つはバンドルを解くことだ」と述べています。Reactはコンポーネントを中心にHTML/CSS/JSをバンドルし、さらにUIライブラリのエコシステムを取り込みました。一方でTailwind CSSは、ReactからCSSを解き放ったとも言えます。同様にTailwind ElementsがReactからUIライブラリを解き放ち、Svelte、Astro、Hotwire、そしてこれから登場するRemix 3等が同じ土俵に立てるようになると、フロントエンドに新しい活気が生まれそうな気がします。
これからの展開が楽しみです。
Views: 0