【スタイル自由】ヘッドレスUIライブラリの紹介

こんにちは、株式会社Gizumoでエンジニアをしている田中です。
サービスを開発するときに工数削減のためにMUIやChakraUI等のUIコンポーネントライブラリを使いたいけど、独自のUI要件や変更を考慮すると導入に勇気がいるという事はありませんか?
今回はそんな懸念を解決してくれるヘッドレスUIライブラリについてご紹介します。
目次
前提・対象とする読者
この記事は以下を前提として読み進めてください。
- サンプルコードは
React
とTypeScript
で記述 - 環境構築や必要なライブラリすべてについては触れない
- 例として出すUIコンポーネントライブラリは
React
に対して提供されているものを中心としている
また、対象とする読者は以下のような方を想定しています。
- UIコンポーネントライブラリ導入を検討中で機能は欲しいけどスタイルは自由に行いたいという希望をお持ちの方
React
やVue
等のJavaScript
のUIフレームワークを知っている方・触ったことがある方
ヘッドレスUIライブラリとは
ヘッドレスUIライブラリとは、スタイルを持たないUIコンポーネントを提供するライブラリです。その代わり、機能とアクセシビリティのみを提供します。そのためライブラリの機能提供に乗っかりながら独自のUIを構築できます。
今回はヘッドレスUIライブラリの1つである、HeadlessUIを使用して実際にコンポーネントを作成しながらヘッドレスUIライブラリの使い方やメリット・デメリットについて見ていきます。HeadlessUI
はTailwindCSSの作成元が作っているライブラリで相性が良いためTailwindCSS
も同時に使用します。
MyTabsコンポーネントの作成
HeadlessUI
が提供してくれるTab
というコンポーネントを使用してMyTabs
コンポーネントを作成します。MyTabs
コンポーネントは最終的に以下のようなUIを持ちます。各タブをクリックすると、対応するコンテンツが表示されます。

最小構成
今回作成するTabコンポーネントの最小構成は以下のコードです。Tab
が実際のボタンでそれに応じたコンテンツがTab.Panel
です。
import { Tab } from '@headlessui/react';
export const MyTabs = () => {
return (
<Tab.Group>
<Tab.List>
<Tab>Tab 1</Tab>
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab>
</Tab.List>
<Tab.Panels>
<Tab.Panel>Tab 1 content</Tab.Panel>
<Tab.Panel>Tab 2 content</Tab.Panel>
<Tab.Panel>Tab 3 content</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
};
最低限の見た目
上記コードの見た目は以下のようになります。スタイルがいっさい付与されていません。しかし、MyTabs
はすでに機能しており、各タブをクリックするとコンテンツが切り替わります。

HTML出力結果
上記コードのHTML
を見ると、以下のようになっています。Tab.Group
は出力されず、Tab.List
とTab.Panels
がdivタグ
として出力されています。詳細を見ると、それぞれにrole属性
やaria-属性
等が付与されており、アクセシビリティへの考慮が確認できます。
MDN Tabの実装を見ると、機能とアクセシビリティを考慮したタブ機能を作るのにかなりの記述量を必要とすることが伺えます。HeadlessUI
のコンポーネントを配置するだけでMDNのページと同等レベルの実装を実現できていることが確認できます。
※aria-属性
はスクリーンリーダー等の支援技術に要素の状態や性質を認識させるために使用します。

スタイルを付与する
スタイルを付与したコードは以下になります。
TailwindCSS
と@headlessui/tailwindcssというプラグインを使用しています。このプラグインを使うと、ui-selected:bg-white
のように状態に応じたスタイルを付与できます。このプラグインを使うとclassName
に変数が入らず可読性の向上を見込めるのと、状態:スタイル
のように記述するため要素の状態とスタイルのマッピングが明確になります。
import { Tab } from '@headlessui/react';
export const MyTabs = () => {
return (
<Tab.Group>
<Tab.List className="flex items-center gap-24 rounded-xl p-2 bg-yellow-400">
<Tab className="p-4 rounded-md bg-transparent ui-selected:bg-white text-white ui-selected:text-yellow-400">
Tab 1
</Tab>
<Tab className="p-4 rounded-md bg-transparent ui-selected:bg-white text-white ui-selected:text-yellow-400">
Tab 2
</Tab>
<Tab className="p-4 rounded-md bg-transparent ui-selected:bg-white text-white ui-selected:text-yellow-400">
Tab 3
</Tab>
</Tab.List>
<Tab.Panels className="mt-2 rounded-xl bg-purple-600 p-12">
<Tab.Panel className="text-white font-bold text-lg">
Tab 1 content
</Tab.Panel>
<Tab.Panel className="text-white font-bold text-lg">
Tab 2 content
</Tab.Panel>
<Tab.Panel className="text-white font-bold text-lg">
Tab 3 content
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
};
スタイルを付与した見た目
上記コードの結果になります。

ヘッドレスUIライブラリのメリット・デメリット
メリット
- 自由なスタイリングが可能
- 機能とアクセシビリティの実装工数削減
メリット:自由なスタイリングが可能
ヘッドレスUIライブラリを使用すれば、自由なスタイリングが可能なため独自のUI要件やUI変更に柔軟に対応できます。たとえばプロダクト独自のデザインシステム等にも対応可能です。MUIやChakraUI等のUIコンポーネントライブラリではこの対応は難しく、一貫性を保つためにデザイナーさんとの密な連携が必要になります。連携工数の削減という意味でもヘッドレスUIライブラリは有用です。
メリット:機能とアクセシビリティの実装工数削減
ヘッドレスUIライブラリを使用すれば、機能とアクセシビリティの実装が不要なため本質的な機能開発に集中できます。たとえばMyTabs
コンポーネントをスクラッチ実装するとstate
で選択の状態を持ちつつ、パネル部分は分岐が必要です。ヘッドレスUIライブラリを使えばその実装をコンポーネントを置くだけで簡単かつ宣言的に実装できます。工数削減と記述量も減るため可読性向上にもつながります。
デメリット
- ライブラリ選定が難しい
- スタイリングに工数が必要
デメリット:ライブラリ選定が難しい
ヘッドレスUIライブラリはまだ、「これを使っておけばOK」というものが存在しないように思います。たとえばGitHub
のスター数を見ているとMUI等のUIコンポーネントライブラリよりも成熟しきっていない印象を受けます。また、ヘッドレスUIライブラリに関する記事も多くはないため、実装例を参考にすることが難しいです。
デメリット:スタイリングに工数が必要
ヘッドレスUIライブラリは0からのスタイリング工数が必要です。スタイリングにはTailwindCSS
等のライブラリを使用することが多いため、ライブラリの学習コストも発生します。MUIやChakraUIのようにコンポーネントを置くだけで見た目まで完結するわけではないため、選定の際にはスタイリング工数を考慮事項として持っておくことは重要です。
※ただし、スタイリングを自由にしたい目的のもとヘッドレスUIライブラリを選定するため、スタイリング工数をデメリットと捉えるかは選定時の要件次第ということになります。
ヘッドレスUIライブラリの紹介
最後にヘッドレスUIライブラリをいくつか紹介して終わりにしたいと思います。以下に紹介しているライブラリは比較的有名なものをピックアップしています。他にも多くのライブラリが存在しますので、興味があれば調べてみてください。
Headless UI
- スター数:
約20k
(2023/06時点) TailwindCSS
と作成元は同じで相性が良いです。コンポーネントはシンプルで使いやすい印象です。コンポーネントの提供数は10種類と少ないです。技術記事は比較的投稿されている印象です。
radix-ui
- スター数:
約10k
(2023/06時点) - コンポーネント単位でプロジェクトにインストール可能でバンドルサイズを抑えます。会社単位で管理されているプロジェクトであり直近のコミット履歴から運用保守の面でも安心です。また、stitches、colors、iconなどのモジュールも提供されておりデザインシステムの構築まで可能です。技術記事も多く上がっており、とても注目されている印象です。
react-aria
- スター数:
約8.8k
(2023/06時点) - adobe社が提供しているプロジェクトです。
Hooks
ベースになっており、プリミティブなDOM要素に対して、Hooks
から取り出したpropsを展開して使用します。DOM要素を自由に配置できカスタマイズが容易な分Hooks
ベースは少し難易度が高いかもしれません。HPには多くのコンポーネントが紹介されています。技術記事はあまり見ない印象です。
ariakit
- スター数:
約6.8k
(2023/06時点) - フォーム系のコンポーネントが豊富です。HPのユースケースがわかりやすく導入には優しそうです。技術記事はほとんど投稿されていない印象です。