【React】React-ToastifyのカラーテーマとPCの外観モードを連動させる方法【TypeScript】

はじめに

Webアプリでユーザー情報の変更などを行った際、処理が正常に完了したことをユーザーに伝えるために、画面の端に一時的にメッセージを表示する機能のことを「トースト」といいます。

トーストとは、主にデスクトップアプリケーションの機能で、情報通知用の小さなウィンドウをディスプレイの下方から一時的にポップアップ表示することである。

トーストとは 「トースト表示, トーストポップアップ」 (Toast): - IT用語辞典バイナリ

トーストを実装するのはそれほど難しくありませんが、プラグインも豊富に提供されているのでそれらを利用すると手軽に導入することができます。今回は、トースト機能を提供するReact-Toastifyというプラグインにおいて、PCの外観モードとトーストのカラーテーマを動的に連動させる方法について説明します。

PCの外観モードとトーストのテーマを連動させる

PCの外観モード

Macの場合、アップルメニュー > システム環境設定 > 一般メニューの中で外観モードを変更することができます。

CSSのprefers-color-schemeを使うことで、Webデザインでも外観モードに合わせたカラーテーマを実装できるようになりました。最近はライトテーマ/ダークテーマ/外観モード準拠のいずれかからカラーテーマを選べるWebサイトが増えてきています。

最近人気のCSSフレームワークであるTailwind CSSでは、クラス名の先頭にdark:をつけるだけで簡単にダークテーマを実装することができます。

React-Toastifyのカラーテーマ

React-Toastifyのカラーテーマはオプションで指定することができます。以下の例では、トーストのカラーテーマとしてdarkを指定しています(6行目)。カラーテーマはlight dark coloredのいずれかを指定することができます。

import { ToastContainer, toast } from 'react-toastify'

function App(){
  const notify = () => {
    toast("Wow so easy!", {
      theme: "dark",
    })
  }

  return (
    <div>
      <button onClick={notify}>Notify!</button>
      <ToastContainer />
    </div>
  )
}

React-ToastifyのカラーテーマはPCの外観モードと連動しているわけではありません。例えば、Tailwind CSSなどを使ってWebサイト全体のカラーテーマをPCの外観モードと連動するようにしていても、React-Toastifyのトーストだけ異なるカラーテーマで表示されてしまう可能性があります。PCの外観モードをダークテーマに設定しており、Webサイトのカラーテーマも連動してダークテーマになっているのに、トーストのカラーテーマだけライトテーマになっていたりすると少し残念です。

React-Toastifyのカラーテーマを動的に設定

React-Toastifyのカラーテーマを動的に設定するには、まずJavaScriptの処理でPCの外観モードを確認します。

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  // PCの外観モードはダークテーマに設定されている
}

この処理を使って、React-Toastifyのカラーテーマに設定する変数を用意します。

let mode = "light"
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  mode = "dark"
}

用意した変数を使ってReact-Toastifyのカラーテーマを設定します。

let mode = "light"
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  mode = "dark"
}
toast("Wow so easy!", {
  theme: mode,
})

さて、JavaScriptであればこれだけで設定できたかと思います。しかし、TypeScriptだと次のような静的解析エラーが出ているはずです。

型 'string' を型 'Theme | undefined' に割り当てることはできません。ts(2322)

string型のmode変数をTheme | undefined型のthemeに設定することはできないというエラー内容です。実は、React-Toastifyのthemeオプションはstring型ではなくTheme型というReact-Toastify内部で定義された型を使用しています。そのため、lightdarkといった単なる文字列が入っているだけの変数を設定しようとすると静的解析エラーが発生するというわけです。

この静的解析エラーが出ていてもWebアプリが動かなくなるわけではありません。それどころか、React-Toastifyのトーストも表示されますし、ちゃんとPCの外観モードと連動したカラーテーマが設定されています。しかし、エラーが残っているのは気持ち悪いし、ちゃんと解決する方法があります。

React-Toastifyのカラーテーマに設定する変数の宣言時に、React-Toastifyのthemeオプションで使用するTheme型を指定します。

let mode: Theme = "light"

React-Toastifyのカラーテーマに設定する変数がTheme型として定義されたため、上記の静的解析エラーは解消されました。しかし、今度は次のような静的解析エラーが出ているかと思います。

名前 'Theme' が見つかりません。ts(2304)

Theme型はReact-Toastify内部で定義された型のため、型定義をインポートする必要があります。

import { ToastContainer, toast, Theme } from 'react-toastify'

これで静的解析エラーはすべて解消されたかと思います。動作確認し、トーストのカラーテーマがPCの外観モードと連動していることを確認してください。まとめると、以下のような実装になります。

import { ToastContainer, toast, Theme } from 'react-toastify'

function App(){
  const notify = () => {
    let mode: Theme = "light"
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
      mode = "dark"
    }
    toast("Wow so easy!", {
      theme: mode,
    })
  }

  return (
    <div>
      <button onClick={notify}>Notify!</button>
      <ToastContainer />
    </div>
  )
}

まとめ

トースト機能を提供するReact-Toastifyというプラグインにおいて、PCの外観モードとトーストのカラーテーマを動的に連動させる方法について説明しました。この方法について検索してみたのですが、明確に解説している情報を見つけることはできませんでした。Stack Overflowで質問している人はいましたが、回答している人はいませんでした。

トースト機能があるとUXが向上し、Webアプリの利便性が向上します。トースト機能を実装するプラグインはいろいろありますが、React-Toastifyは簡単に導入でき、デザインに優れ、カスタマイズ性も高いので非常におすすめです。

関連記事

RailsアプリにおけるReactの使い方や注意点など
# はじめに [こちらのページ](https://qiita.com/TsutomuNakamura/items/72d8cf9f07a5a30be048)でReactの基本について勉強しました。 Railsアプリの中でReactを利用するとい [...]
2019年12月13日 12:37
【Rails】Railsアプリにreact-railsを追加する手順
# はじめに JavaScriptフレームワークといえば長らくjQuery一強でした。しかし、ここ数年はAngularJSやReact、Vue.jsといった新しいフレームワークがどんどんと登場しています。過去5年間の検索回数の推移を見てみると、2 [...]
2019年12月11日 15:21