8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クラベスAdvent Calendar 2024

Day 16

【Headless UI入門】もうスタイルに悩まない!Headless UIで自由なデザインを実現する方法

Last updated at Posted at 2024-12-15

はじめに

今回ですが、最近トレンドになっているHeadless UIについて概要と、魅力について以下の記事を参考に、記事を書いていきます。
Headless UIについて、最近よく耳にするという方も、初めての方も、本記事を見たら、その魅力が伝わると思いますし、標準で使っていく気になると思います。

Headless UI ライブラリとは

Headless UI ライブラリとは、その名の通り、デザインのないUIライブラリのことです。
デザインがない以外の特徴としては、アクセシビリティ対応が組み込まれていたり、Tailwind CSSなどの他のスタリングツールと併用して使用することができることが挙げられます。

つまり、非HeadlessなUIライブラリとは異なり、Headlessではスタイルと機能の柔軟性が高くなるということです。さらには、Headless ライブラリではデフォルトでスタイルなしのコンポーネントが提供されるため、開発者がカスタムしたスタイルとの競合が発生しないという大きなメリットがあります。

この柔軟性により、Radix UIHeadlessUIなどのHeadless ライブラリが新しいプロジェクトの標準になりました。

さらに、最近では、shadcn/uiJustdなどHeadless UIライブラリ上に構築されたコンポーネントライブラリを使用することが標準になりつつあります。あのMaterial UIでさえ独自のHeadless コンポーネントライブラリ としてBase UIを開発しています。
shadcn/uiはRadix UI上に、JustdはReact Aria上に構築されたコンポーネントライブラリです)

Headless コンポーネントライブラリが標準となる理由

では、なぜHeadless コンポーネントライブラリが標準になるのでしょうか。
(私は今後、ますますHeadless UIは伸びると思っています)

いくら、柔軟性が高いとはいえ、Material UIのように予めスタイリングされたコンポーネントを使ったほうが、開発スピードは速いはずですし、実際、予めスタイリングされたコンポーネントでデザインを構築してUIを開発する手法は賢い戦略と言えます。

しかしながら、このような戦略は大きな欠点をはらんでいます。
それは独自のスタイル設定が非常に難しいという点です。

どういうことか解説します。
Material UIなど従来の非Headless コンポーネントライブラリはデフォルトスタイルを持っています。
これはパット見は便利ですが、カスタマイズ性が低く、設定が難しいという側面も持っています。

Material UIを例にとりましょう。
あるアプリケーション開発において、完全にMaterial UIのコンポーネントが提供するスタイリングのみで構築するという前提であれば、先程の戦略は功を奏します。

ただ、そのようなアプリケーションはほとんどなく、たいていのアプリケーション開発では、スタイリングのカスタマイズが必要です。

実際にコードにして比較してみましょう。

Material UI

Material UIの場合、大抵のスタイルはsxpropsでスタイリングできますが、より細かなスタイルは以下のような煩雑な手順を踏む必要があります。

  1. Material UIの特定のクラスをoverrideすること
  2. 素のCSSをあてること

また、これらの設定がMaterial UIの特定のクラスの子孫クラス・セレクターにも及ぶ可能性があり、その都度、クラス名やセレクター名をdevtools等で特定し、素のCSSでoverrideする必要性もあります。
(ちなみに、Material UIはドキュメントも見づらいので、ドキュメントから探そうものなら、それだけで日が暮れる覚悟で労力を投下する必要があります)

どうでしょうか。
この説明と以下のコード及び、このスタイリングコードがさらに肥大化する可能性を考えると、Headless UI上に構築されていないコンポーネントライブラリを使用するのは、かなりしんどいと感じるのではないでしょうか。

import Switch from '@mui/material/Switch'

const MuiSwitch = () => {
  return (
    <Switch
      sx={{
        "&.MuiSwitch-root .MuiSwitch-thumb": {
            backgroundColor: "red"
         }
      }}
    />
  )
}

ここまでで、細かいスタイルの適用は非Headlessのコンポーネントライブラリではかなり難しいということがわかったと思います。

次にHeadlessUIの方を見てみましょう。

Radix UI + Tailwind CSS

import * as Switch from "@radix-ui/react-switch"

const HeadlessSwitch = () => {
  return (
    <Switch.Root>
      <Switch.Thumb className="bg-red-600" />
    </Switch.Root>
 )
}

明らかにシンプルになっていることがわかります。

つまり、Headless vs 非Headlessの結果は言うまでもなく、Headlessに軍配が上がります。

非HeadlessではUI構築という本質的な部分を行うよりコンポーネントライブラリとの格闘という非本質的な部分に多くの時間を割かれることになります。

ところが、Headless UIのコンポーネントライブラリを使用するとUI構築の部分に真に集中することができるようになります。

だからこそ、Headless UIで構築されたコンポーネントライブラリが、今後ますます伸びるし標準になると予想されているのです。

そして、実際に、Radix UITailwind CSSで構築された、コピペ可能なコンポーネントライブラリのshadcn/uiが流行っており、コピペ可能なコンポーネントライブラリとしてトレンドとなっています。
shadcn/uiに関しては、昨年のGitHub獲得Star数(JSライジング・スター2023)は1位を獲得したのは記憶に新しいところと思います。

また、最近では先程紹介した、React AriaTailwind CSSで構築されたコピペ可能なコンポーネントライブラリであるJustdもでてきています。

私は最近の個人開発や学習ではJustdをメインに使っているのですが、自動レスポンシブ対応されていたり、開発者がこれは使うだろうなという機能をコンポーネント + propsとして提供してくれているので、こちらもメンテが盛んになれば、流行ると思っています。

おわりに

どうでしょうか?
Headless コンポーネントライブラリに対するモチベーションが湧いたことを願っていますが、最後に参考記事の一文を紹介したいと思います。

今後も多くのheadless UIライブラリがでてくるでしょうし、既存のものはさらに改良が進んでReactのエコシステムにより良い影響を及ぼす

私も著者の意見に賛同しますし、上記のようになることを信じています。ただ、日本ではまだまだ、主流とは言えないのが残念としか言えないので、もっとトレンドになってほしいところではあります。

Headless UIライブラリの使用実績の有無に囚われず、本質的な部分であるUIの構築に集中できることを満たしてくれるかをベースに考えていきたいところですね。

おまけ

実際に非Headless コンポーネントライブラリのMaterial UIとHeadless コンポーネントライブラリの細かなスタイリングをしたものを作成してみたので、比較してみましょう。

非Headless コンポーネントライブラリの場合

以下はMantineでいうところのoutlineのTabになります。

const MuiTabs = () => {
  return (
    <Tabs
      TabIndicatorProps={{
        style: {
          display: 'none',
        },
      }}
      sx={{
        px: 8,
        position: 'relative',
        '& .MuiTabs-flexContainer': {
          gap: 0.1,
        },
        '&::before': {
          content: '""',
          position: 'absolute',
          width: '100%',
          height: '1px',
          bottom: 0,
          bgcolor: 'red',
          zIndex: 0,
        },
        '&::after': {
          content: '""',
          position: 'absolute',
          height: '1px',
          width: '100%',
          left: 0,
          bottom: 0,
          bgcolor: 'red',
          zIndex: 0,
        },
      }}
    />
  )
}

const MantineTab = () => {
  return (
    <Tabs variant="outline" />
  )
}

率直に言って「やってられない」というニュアンスが伝わったのではないかと思います。

実際、かなりライブラリと格闘しました。
特定のpropsを探し出し、デフォルトスタイルを打ち消したり、特定クラスを探し出し、素のCSSでスタリング及びoverrideしないとoutlineのTabはできなかったです。

逆に素のCSSだけでやっているMantineは神ライブラリと言えるでしょう。

Headless UIコンポーネントの場合

では、上記のMaterial UIとMantineのTabsと同様のスタリングをHeadless コンポーネントライブラリのJustdのTabsでやってみましょう。
実際に、JustdTailwind CSSで少しカスタマイズするだけでできそうです。
shadcn/uiも同じことが言えそうです)

以下の画像が、デフォルトのTabsインストール時と変更時の比較です。

Tailwind CSSだけで行えるので、かなり楽ですし、特定のクラスやセレクタを調査する必要なく、簡単に実装できました。

また実際のメインのページコンポーネントでは、Tabsを使用していますが、スタリングの肥大化はしていないことを確認できます。

とはいえ、そこそこ変更しているので、やはりMantineがすごいと言わざるを得ないという検証結果となりそうです。

タブ呼び出し部分

image.png

実際にインストールしたコンポーネント部分

image.png

image.png

image.png

参考文献

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?