📚

【React】ダイアログライブラリの調査

2024/05/14に公開

Reactの既存サービスにダイアログのUIライブラリを入れる可能性があったので調査。
既存サービスなので、スタイルが含まれていない「headless UIライブラリ」を中心に見ていく。[1]
WAI-ARIAのDialog (Modal) PatternAlert and Message Dialogs Patternを理解している前提で記事を書く。

Tailwind CSS - HeadlessUI

ダイアログに当たるコンポーネントは1つ。

問題点

ダイアログを複数開く場合、ダイアログをネストする必要がある。(ref: https://github.com/tailwindlabs/headlessui/issues/2876#issuecomment-1849866552
正常系のUIでダイアログが重なることが想定されている場合ならネストして組めるが、例えば複数APIのエラー表示を行いたい場合などに困る。
ちなみにネストせずにダイアログを表示すると、ダイアログは表示されるが閉じることができなかった。

Radix UI - Radix Primitive

WAI-ARIAと同様に、ダイアログに当たるコンポーネントが2つある。

問題点

ダイアログを表示するとbodyにmarginとpaddingが指定されてしまう。下記は例。

body {
    overflow: hidden !important;
    position: relative !important;
    padding-left: 0px;
    padding-top: 0px;
    padding-right: 0px;
    margin-left: 0;
    margin-top: 0;
    margin-right: 0px !important;
}

これはライブラリが依存しているreact-remove-scroll-barに因るもので、issueでも言及されている記事に拠ると、読み違えていなければWindowsのブラウザのスクロールを止めるために必要なものらしい。

bodyにmarginとpaddingが指定されていなければ問題ないが、弊サービスには合致しなかった。

Chakra UI - Ark UI

ダイアログに当たるコンポーネントは1つ。

注意点

  • ドキュメントのAPIのデフォルト値が記載されていないものが多い。
  • デフォルトでオフになっているlazyMountやunmountOnExitをtrueにしない場合、非表示時にもダイアログコンポーネントがmountされるが、非表示の制御がhidden属性のみに頼っているので、ダイアログでdisplayプロパティを使っている場合は表示されてしまう。
    • → lazyMountとunmountOnExitをtrueにすれば問題ない。
  • closeOnEscapeが正常に動作しない。
    • onOpenChangeで開閉制御している場合、trueにしてもfalseにしても指定しなくても、Escキーでダイアログが閉じてしまう。
    • おそらくバグ? issue: https://github.com/chakra-ui/ark/issues/2426
    • Escキーでダイアログを閉じないようにしたい場合、onOpenChangeを指定しない必要がある。
      • これをすると、「ダイアログの外側をクリックしたときに閉じる」という制御ができず、やりたい場合自前実装することになりそう。

MUI - MUI Core - Base UI

  • https://github.com/mui/base-ui
    • 最終更新2時間前(執筆時点)
    • 120 stars(執筆時点)
    • PR見てくれていそう。
  • チーム開発。
    • https://mui.com/about/
    • チームに載っているのは35人。
    • 「MUI は世界各地から貢献する、グローバルな完全リモートのチームおよびコミュニティです。」
  • バージョンがbetaとalphaしかない。
  • 最適なアクセシビリティ

ダイアログに当たるコンポーネントは1つ。

注意点

  • バージョンがbetaとalphaしかない。
  • デフォルトのroleがなぜかpresentation。
    • 上書きはできる。
  • modal全体を包むroot、背景(backdrop)の宣言が宣言的じゃない。
    • こんな感じ。
<Modal
    open={isOpen}
    onClose={onClose}
    slots={{
        root: 'div',
        backdrop: 'div'
    }}
    slotProps={{
        root: {
            className: 'AlertDialogOverlay',
            role: 'alertdialog'
        },
        backdrop: {
        }
    }}
>

その他dialog特化のライブラリ

いい感じのライブラリはあっても、メンテナンスされていなかったりで採用しづらかった。

脚注
  1. Tailwind CSSが作っている「HeadlessUI」は「headless UIライブラリ」の1つ ↩︎

Discussion