1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Vite × React × TypeScript】Chakra UI v3でトーストの閉じるボタンを表示・機能させる方法

Last updated at Posted at 2024-12-10

はじめに

お疲れ様です。りつです。

今回は、タイトルの通りChakra UI v3のトーストにまつわるtipsをご紹介します。

問題

Chakra UIの v1、v2まではトーストにisClosableというオプションがあり、このオプションがtrueだとトーストの閉じるボタンが表示されていたようです。

しかし、Chakra UI v3だとこのオプション自体がエラーになってしまい使用できませんでした。

どうにかして表示できないものかといろいろ試してみたところ、以下のように表示させることができたので、その方法をご紹介します。

image.png

image.png

解決方法

トーストの閉じるボタンを機能させるために以下を実施します。

  1. トーストの閉じる機能の有効化
  2. トーストの閉じるボタンを見やすく調整

1. トーストの閉じる機能の有効化

まず、トーストの閉じる機能を有効化する必要があります。
こちらは、toaster.createに指定するオプションで、meta.closableを設定します。

具体的には、以下のソースコードをご参照ください。

src/hooks/useMessage.ts
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の呼び出し元
src/hooks/useAuth.ts
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コンポーネントの呼び出し元
src/App.tsx
import { Router } from '@/router/Router'
import { Toaster } from "@/components/ui/toaster"

function App() {
  return (
    <>
      <Toaster />
      <Router />
    </>
  )
}

export default App

2. トーストの閉じるボタンを見やすく調整

続いて、トーストの閉じるボタンのスタイルを調整します。

デフォルトだとなぜか閉じるボタンがほぼ目視できない上に、ものすごく小さく表示されておりクリックしずらく、視認性が悪いです。

  • 【 参考 】トーストの閉じる機能ON時の表示(閉じるボタンが表示されていないように見えますが、極小サイズで存在はしており、うまくクリックすると閉じることが可能です)
    image.png

そのため、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>
      )
    }
    

以上の手順で、トーストの閉じるボタンを表示・機能させることができます。

おわりに

今回は調べても情報がなかなか得られませんでした。

ソースコードを辿って推測しながら動かしてみた結果、トーストの閉じるボタンを機能させることができました。

もっと適切な方法があるかもしれませんので、ご存じの方がいたらぜひ教えてください。

参考

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?