はじめに
お疲れ様です。りつです。
今回は、タイトルの通りChakra UI v3のトーストにまつわるtipsをご紹介します。
問題
Chakra UIの v1、v2まではトーストにisClosable
というオプションがあり、このオプションがtrue
だとトーストの閉じるボタンが表示されていたようです。
しかし、Chakra UI v3だとこのオプション自体がエラーになってしまい使用できませんでした。
どうにかして表示できないものかといろいろ試してみたところ、以下のように表示させることができたので、その方法をご紹介します。
解決方法
トーストの閉じるボタンを機能させるために以下を実施します。
- トーストの閉じる機能の有効化
- トーストの閉じるボタンを見やすく調整
1. トーストの閉じる機能の有効化
まず、トーストの閉じる機能を有効化する必要があります。
こちらは、toaster.create
に指定するオプションで、meta.closable
を設定します。
具体的には、以下のソースコードをご参照ください。
import { toaster } from "@/components/ui/toaster"
import { useCallback } from "react"
type Props = {
title: string;
type: "info" | "warning" | "success" | "error";
}
export const useMessage = () => {
const showMessage = useCallback((prpps: Props) => {
const { title, type } = prpps;
toaster.create({
title,
type,
duration: 2000,
meta: { closable: true } // トーストを閉じる処理を有効化
})
}, []);
return { showMessage }
}
【 参考 】showMessageの呼び出し元
import { useCallback, useState } from "react";
import { useNavigate } from "react-router";
import axios from "axios";
import { User } from "@/types/api/user";
import { useMessage } from "./useMessage";
export const useAuth = () => {
const navigate = useNavigate();
const { showMessage } = useMessage();
const [loading, setLoading] = useState(false);
const login = useCallback((id: string) => {
setLoading(true);
axios.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => {
if (res.data) {
showMessage({ title: 'ログインしました', type: 'success' });
navigate('/home');
} else {
showMessage({ title: 'ユーザーが見つかりません', type: 'error' });
}
})
.catch(() => showMessage({ title: 'ログインできません', type: 'error' }))
.finally(() => setLoading(false));
}, [navigate, showMessage]);
return { login, loading };
};
【 参考 】Toasterコンポーネントの呼び出し元
import { Router } from '@/router/Router'
import { Toaster } from "@/components/ui/toaster"
function App() {
return (
<>
<Toaster />
<Router />
</>
)
}
export default App
2. トーストの閉じるボタンを見やすく調整
続いて、トーストの閉じるボタンのスタイルを調整します。
デフォルトだとなぜか閉じるボタンがほぼ目視できない上に、ものすごく小さく表示されておりクリックしずらく、視認性が悪いです。
そのため、src/components/ui/toaster.tsx
の<Toast.CloseTrigger/>
コンポーネントにスタイルを設定して、見やすく調整していきます。
上記ファイルは以下のコマンドを実行すると自動生成されます。
npx @chakra-ui/cli snippet add toaster
If you don't already have the snippet, run the following command to add the
toaster
snippet
- 修正前
src/components/ui/toaster.tsx
"use client" import { Toaster as ChakraToaster, Portal, Spinner, Stack, Toast, createToaster, } from "@chakra-ui/react" export const toaster = createToaster({ placement: "bottom-end", pauseOnPageIdle: true }) export const Toaster = () => { return ( <Portal> <ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}> {(toast) => ( <Toast.Root width={{ md: "sm" }}> {toast.type === "loading" ? ( <Spinner size="sm" color="blue.solid" /> ) : ( <Toast.Indicator /> )} <Stack gap="1" flex="1" maxWidth="100%"> {toast.title && <Toast.Title>{toast.title}</Toast.Title>} {toast.description && ( <Toast.Description>{toast.description}</Toast.Description> )} </Stack> {toast.action && ( <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger> )} {toast.meta?.closable && <Toast.CloseTrigger/>} </Toast.Root> )} </ChakraToaster> </Portal> ) }
- 修正後
src/components/ui/toaster.tsx
"use client" import { Toaster as ChakraToaster, Portal, Spinner, Stack, Toast, createToaster, } from "@chakra-ui/react" export const toaster = createToaster({ placement: "top", // 表示位置をページ上部に指定(任意) pauseOnPageIdle: true }) export const Toaster = () => { return ( <Portal> <ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}> {(toast) => ( <Toast.Root width={{ md: "sm" }}> {toast.type === "loading" ? ( <Spinner size="sm" color="blue.solid" /> ) : ( <Toast.Indicator /> )} <Stack gap="1" flex="1" maxWidth="100%"> {toast.title && <Toast.Title>{toast.title}</Toast.Title>} {toast.description && ( <Toast.Description>{toast.description}</Toast.Description> )} </Stack> {toast.action && ( <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger> )} {toast.meta?.closable && <Toast.CloseTrigger style={{width:'25px', height:'25px', color: 'white'}} _hover={{ cursor: 'pointer' }}/> } {/* Toast.CloseTriggerに対してスタイルを設定 */} </Toast.Root> )} </ChakraToaster> </Portal> ) }
以上の手順で、トーストの閉じるボタンを表示・機能させることができます。
おわりに
今回は調べても情報がなかなか得られませんでした。
ソースコードを辿って推測しながら動かしてみた結果、トーストの閉じるボタンを機能させることができました。
もっと適切な方法があるかもしれませんので、ご存じの方がいたらぜひ教えてください。
参考