Headless UI: スタイルなしの、アクセシブルなUIコンポーネント

Adam Wathan

現代的なWebアプリケーションを構築する際の最大の課題の1つは、セレクトメニュー、ドロップダウン、トグル、モーダル、タブ、ラジオグループなどのカスタムコンポーネントを構築することです。これらのコンポーネントはプロジェクトごとに非常によく似ていますが、完全に*同じ*ということはありません。

既製のパッケージを使用することもできますが、通常、独自のスタイルと密接に結びついています。そのため、プロジェクトのルックアンドフィールに合わせるのが非常に難しく、ほとんどの場合、CSSのオーバーライドを大量に記述する必要があり、Tailwind CSSを使用している場合は大きな後退のように感じられます。

もう1つの選択肢は、独自のコンポーネントを最初から構築することです。最初は簡単そうに見えますが、キーボードナビゲーション、ARIA属性の管理、フォーカストラップのサポートを追加する必要があることを思い出し、気が付くと、完全に信頼性の高いドロップダウンメニューを構築するのに3〜4週間を費やしています。

私たちはもっと良い選択肢があると考えており、それを構築しています。

Headless UIは、完全にスタイルなしの、完全にアクセシブルなReactおよびVue用のUIコンポーネントのセット(そして間もなくAlpine.js)であり、複雑な実装の詳細を自分で心配することなく、シンプルなユーティリティクラスで最初からスタイルを設定する機能を犠牲にすることなく、これらの種類のカスタムコンポーネントを簡単に構築できるようにします。

Headless UI Logo

@headlessui/reactを使用してカスタムドロップダウン(ライブラリに含まれる多くのコンポーネントの1つ)を構築するとどうなるかを示します。完全なキーボードナビゲーションサポートとARIA属性管理を備え、シンプルなTailwind CSSユーティリティでスタイル設定されています。

import { Menu } from "@headlessui/react";
function MyDropdown() {
return (
<Menu as="div" className="relative">
<Menu.Button className="rounded bg-blue-600 px-4 py-2 text-white ...">Options</Menu.Button>
<Menu.Items className="absolute right-0 mt-1">
<Menu.Item>
{({ active }) => (
<a className={`${active && "bg-blue-500 text-white"} ...`} href="/account-settings">
Account settings
</a>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a className={`${active && "bg-blue-500 text-white"} ...`} href="/documentation">
Documentation
</a>
)}
</Menu.Item>
<Menu.Item disabled>
<span className="opacity-75 ...">Invite a friend (coming soon!)</span>
</Menu.Item>
</Menu.Items>
</Menu>
);
}

この例では、それに関連するコードを1行も記述せずに、無料で得られるものは次のとおりです。

  • ドロップダウンパネルは、クリック、スペースバー、Enterキー、または矢印キーを使用すると開きます。
  • ドロップダウンは、Escapeキーを押すか、外側をクリックすると閉じます。
  • 上下の矢印キーを使用して項目をナビゲートできます。
  • Homeキーを使用して最初の項目にジャンプし、Endキーを使用して最後の項目にジャンプできます。
  • キーボードでナビゲートすると、無効な項目は自動的にスキップされます。
  • キーボードでナビゲートした後、マウスで項目をホバーすると、マウス位置ベースのフォーカスに切り替わります。
  • キーボードでナビゲート中に、項目はスクリーンリーダーに適切にアナウンスされます。
  • ドロップダウンボタンは、メニューを制御するものとしてスクリーンリーダーに適切にアナウンスされます。
  • …そして、おそらく私が忘れているさらに多くの機能があります。

すべて、コードのどこにもariaという文字を記述したり、単一のイベントリスナーを記述したりすることなく実現できます。そして、デザインを完全に制御できます!

このコンポーネントには3000行を超えるテストがあります。自分でそれを行う必要がなかったのは素晴らしいですよね?

これが完全にスタイル設定されたライブデモですTailwind UIから取得)。実際に動作している様子を確認できます。

キーボードまたはスクリーンリーダーで試して、その良さを実感してください!

v0.2.0をタグ付けしました。現在、次のコンポーネントが含まれています。

詳細を学び、深く掘り下げるには、Headless UIのウェブサイトにアクセスしてドキュメントをお読みください。


ここ数年、私のオンラインでの活動を追っている方なら、レンダーレスUIコンポーネントに私が魅了されていたことを覚えているかもしれません。これは、2017年末に向けて私が本当に興味を持ち始めたものです。私は長年このようなライブラリが存在することを望んでいましたが、チームを拡大し始めるまで、それを実現するためのリソースがありませんでした。

今年の初めにRobin Malfaitを雇用しました。彼はそれ以来、Headless UIにフルタイムで取り組んでいます。

このプロジェクトの最大の動機は、Tailwind UIに本番環境対応のJSの例を追加したいということです。Tailwind UIは現在、HTMLのみで、JavaScriptは自分で用意する必要があるプロジェクトです。これは、すべての動作を完全に制御したい多くのお客様にとっては素晴らしいことですが、他の多くのお客様にとっては摩擦の原因となっています。

すべてのコンポーネントの例に200行もの厄介なJSを追加したくなかったので、実際のUIデザインの柔軟性を損なうことなく、それらのノイズをすべて抽出する方法としてHeadless UIの開発に着手しました。

なぜ車輪の再発明をするのか?

この問題に取り組もうとしたのは私たちが最初ではありません。Downshiftは、2017年にこのアイデアに私が興奮した最初のライブラリでした。Reach UIReakitは2018年に開発を開始し、React Ariaはごく最近、今年の初めにリリースされました。

いくつかの理由から、私たちはこの問題に対する私たち自身のアプローチを試すことにしました。

  • 既存のソリューションはほぼ完全にReactに焦点を当てていますが、これらのアイデアをVue、Alpine、そして将来的にはさらに多くのエコシステムに導入したいと考えています。
  • これらのライブラリは、Tailwind UIにJSサポートを追加するための基盤となるものであり、それがビジネスを継続させているものであるため、ライブラリの動作とサポート内容について完全な意思決定権を持つことが重要だと感じました。
  • 私たちは、これらのコンポーネントのAPIがどのようなものであるべきかについて独自のアイデアを持っており、それらのアイデアを自由に探求したいと考えています。
  • カスタムCSSを記述するのではなく、Tailwindでこれらのコンポーネントを常に非常に簡単にスタイル設定できるようにしたいと考えています。

私たちがこれまでに考え出したものは、柔軟性と開発者エクスペリエンスの間の素晴らしいバランスを実現していると考えており、私たちが学び、アイデアを共有できる同様の問題に取り組んでいる他の人々がいることに感謝しています。

次は何?

Headless UI向けに開発するコンポーネントはまだたくさんあります。以下を含みます:

  • モーダル
  • ラジオグループ
  • タブ
  • アコーディオン
  • コンボボックス
  • 日付ピッカー

…そして、おそらくさらに多く。また、Alpine.jsのサポートにも着手しようとしており、年末近くにReact、Vue、Alpineのv1.0をタグ付けできることを願っています。

その後、他のフレームワークの調査を開始し、最終的にはSvelte、Angular、Emberなどのエコシステムに、ファーストクラスまたはコミュニティパートナーと協力して、同じツールを提供できることを期待しています。

私たちの活動を常に把握したい場合は、GitHubでプロジェクトをフォローしてください。

この記事について話しませんか? GitHubで議論する →

すべての最新情報を直接受信箱に届けます。
ニュースレターに登録してください。

Copyright © 2025 Tailwind Labs Inc.·商標ポリシー