React Ariaを使用したモーダル作成

はじめに

こんにちは
株式会社TOKOSのナオキです。
今回はReactのライブラリであるReactAriaを使用してモーダルの作成をしていきます。

対象読者

  • React初学者の方
  • React Ariaを使用して開発をされる方

React Ariaとは

React AriaはAdobeが提供しているアクセシビリティに特化したヘッドレスUIライブラリです。

React Ariaは、スクリーンリーダーキーボードナビゲーションのサポートで、視覚障害と運動障害の側面に対応しています。
ウェブサイトを作るとき、見た目や動作が良くても、アクセシビリティが考慮されていないと、多くのユーザーにとって使いにくいものになってしまいます。React Ariaを使うと、アクセシビリティに関する複雑な設定を簡単に行え、より多くの人にとって使いやすいウェブサイトを作ることができます。

アクセシビリティとは、利用者の障害などの有無や年齢や利用環境にかかわらず、あらゆる人々がウェブサイトで提供されている情報やサービスを利用できることです。

ヘッドレスUIとは、UI要素やインタラクションのロジック、状態、処理、APIを提供し、マークアップやスタイルを提供しないライブラリを指す言葉です。

スクリーンリーダーとは、視覚障害者や読み込みの遅いユーザーなど、視覚的な情報を認識できないユーザーがウェブサイトやアプリケーションを利用する際に使用する支援技術の一種です。

キーボードナビゲーションとは、キーボードを使ってウェブサイトやアプリケーションを操作することです。

React Ariaのアクセシビリティに関して詳しく知りたい方は、以下のリンクから公式ドキュメントを参照してください。


React Ariaにはアクセシビリティ対応のされたさまざまなコンポーネントがあります。
主なコンポーネントを以下で紹介します!

React Ariaの主なコンポーネント

コンポーネント説明
Buttonマウス、タッチ、キーボードで操作できるボタンを作成をできます
FileTriggerファイルシステムにアクセスができるボタンを作成できます
ToggleButton2つの状態やモードを切り替えるトグルボタンを作成できます
GridListインタラクティブなアイテムのリストを表示し、
1つまたは複数の選択ができ、行ごとのアクションをサポートできます
ListBoxオプションのリストを表示し、1つまたは複数のオプションを選択できます
Menuユーザーが選択できるアクションやオプションのリストが表示できます
Table行と列でデータを表示できます。オプションで行の選択や並び替えができます
TagGroupラベル、カテゴリー、その他のアイテムの選択が可能なリストです
Calendarカレンダーを表示し、1つの日付を選択することが出来ます
DateFieldキーボードを使って日付と時刻の値を入力し、編集することができます
DatePickerCalendarポップオーバーとDateFieldを組み合わせて、日付と時刻の値を入力または選択できます
DateRangePicker日付と時間の範囲を入力または選択できます
TimeFieldキーボードを使って時間値を入力・編集できます
DropZone1つまたは複数のオブジェクトをドラッグ&ドロップできるエリアのことです
Checkbox1つまたは複数のアイテムを選択済みとしてマークすることができます
Formデータをサーバーに送信するための入力グループのことです
フィールドの検証エラーを提供するためのサポートもあります
RadioGroup相互に排他的なオプションのリストから1つの項目を選択することができます
Switch設定をオンまたはオフにすることができます
TextFieldキーボードでテキストの値を入力ができます
Breadcrumbs現在のページや階層がわかるパンくずリストを表示できます
Dialog現在の画面の上にダイアログを表示できます
Modal現在の画面の上にモーダルを表示できます
Tooltipホバーまたはフォーカス時に要素の説明を表示できます
ComboBoxテキスト入力とリストボックスを組み合わせたもので、クエリにマッチする項目を選択肢のリストから絞り込むことができます

これらのコンポーネントを複数使用し組み合わせることで、多様な実装をすることができます!

詳しく知りたいと言う方は以下のリンクから公式ドキュメントを参照してください。

実装

開発環境

今回cssはtailwindcssを使用します。

  • react: ^18,
  • react-aria-components: ^1.2.1,
  • tailwindcss: ^3.4.1,

React Ariaの導入


npmやyarmを使用してReact Arisをインストールすることができます。

$ npm install react-aria-components

または

$ yarn add react-aria-components

これでReact Ariaのインストールは完了です!

次にReact AriaのModalコンポーネントを使用して、モーダルを作成します。

コード

上記で紹介したコンポーネントを以下のように組み合わせることで簡単にモーダルを作成することが出来ます。
ヘッドレスUIなのでプロダクトごとのデザインに合うスタイルを指定することができます。(tailwindcssでスタイルをあてています。)

import {
  Button,
  Calendar,
  CalendarCell,
  CalendarGrid,
  DateInput,
  DatePicker,
  DateSegment,
  Dialog,
  DialogTrigger,
  Group,
  Heading,
  Input,
  Label,
  ListBox,
  ListBoxItem,
  Modal,
  Popover,
  Select,
  SelectValue,
  TextField,
} from "react-aria-components"

export default function BlogPage() {
  return (
    <div className="mt-10 flex justify-center">
      <DialogTrigger>
        <Button className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-700">
          モーダルを開く
        </Button>
        <Modal className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
          <Dialog className="w-[600px] rounded-lg border border-gray-400 bg-white p-6 shadow-lg outline-none">
            {({ close }) => (
              <form>
                <Heading
                  slot="title"
                  className="mb-4 border-b-2 text-lg font-semibold"
                >
                  モーダル
                </Heading>
                <div className="flex flex-col gap-6">
                  <TextField autoFocus>
                    <Label className="mb-1 block">タイトル</Label>
                    <Input className="w-full rounded border border-gray-300 p-2" />
                  </TextField>
                  <TextField autoFocus>
                    <Label className="mb-1 block">内容</Label>
                    <Input className="w-full rounded border border-gray-300 p-2" />
                  </TextField>
                  <Select className="flex flex-col">
                    <Label>選択肢</Label>
                    <Button className="flex w-fit gap-3 rounded-md border px-4 py-2">
                      <SelectValue />
                      <span
                        aria-hidden="true"
                        className="rounded-md border px-1"
                      >
                        ▼
                      </span>
                    </Button>
                    <Popover>
                      <ListBox className="flex flex-col gap-2 bg-gray-100 p-4">
                        <ListBoxItem>リンゴ</ListBoxItem>
                        <ListBoxItem>バナナ</ListBoxItem>
                        <ListBoxItem>パイナップル</ListBoxItem>
                        <ListBoxItem>ブドウ</ListBoxItem>
                      </ListBox>
                    </Popover>
                  </Select>
                  <DatePicker>
                    <Label>日付</Label>
                    <Group className="flex w-fit gap-3 rounded-md border px-4 py-2">
                      <DateInput className="flex gap-1">
                        {(segment) => <DateSegment segment={segment} />}
                      </DateInput>
                      <Button className="rounded-md border px-1">▼</Button>
                    </Group>
                    <Popover>
                      <Dialog>
                        <Calendar className="bg-gray-100 p-4">
                          <header className="flex w-[200px] justify-between gap-6">
                            <Button slot="previous">◀</Button>
                            <Heading />
                            <Button slot="next">▶</Button>
                          </header>
                          <CalendarGrid className="w-[200px]">
                            {(date) => <CalendarCell date={date} />}
                          </CalendarGrid>
                        </Calendar>
                      </Dialog>
                    </Popover>
                  </DatePicker>
                  <Button
                    onPress={close}
                    className="w-fit rounded-md border bg-blue-500 px-6 py-3 text-white hover:bg-blue-700"
                  >
                    送信
                  </Button>
                </div>
              </form>
            )}
          </Dialog>
        </Modal>
      </DialogTrigger>
    </div>
  )
}

作成したモーダル

このようによく目にするようなモーダルを作成することができました。
サンプル動画ではマウスを使わずキーボード操作のみでモーダルの開閉、操作をしています。
このようなアクセシビリティ対応がされたモーダルを簡単に作成することができます!

おわりに

今回はReactのライブラリであるReact Ariaを使用してモーダルの作成を行いました。
簡易的なモーダルを作成しましたが、用途によってはもっと沢山の入力欄を設けたいときなどあると思います。React Ariaのアクセシビリティ対応の豊富なコンポーネントであれば大抵のことは出来ると思いますので、ぜひ使用してみてはいかがでしょうか!