HextaUI

Toast

きれいに積み重なり、ホバーで展開し、スワイプで消せる短いメッセージです。読み込み中の状態をその場で成功またはエラーに切り替えます。

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ToastDemo() {
  return (
    <Button
      variant="outline"
      onClick={() =>
        toast("Event created", {
          description: "Sunday, December 3 at 9:00 AM",
          action: { label: "Undo", onClick: () => toast("Event removed") },
        })
      }
    >
      Show toast
    </Button>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/toast.json

コンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。

アプリのルート付近に <Toaster /> を一度だけ追加します。

import { Toaster } from "@/components/ui/toast"

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Toaster />
      </body>
    </html>
  )
}

あとは、React コンポーネントの外を含め、どこからでも toast を呼び出します。

import { toast } from "@/components/ui/toast"

toast("Event created", { description: "Sunday at 9:00 AM" })
toast.success("Payment received")
toast.promise(save(), { loading: "Saving…", success: "Saved", error: "Couldn't save" })

toast は最新のものを手前にして、きれいに積み重なります。積み重なった部分にホバーまたはフォーカスすると扇状に広がり、読んでいる間はすべてのタイマーが一時停止します。toast を端に向かってスワイプすると閉じます。

タイプ

すべての toast は同じ落ち着いた面を使い、色を持つのはアイコンだけです。

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ToastTypes() {
  return (
    <div className="flex flex-wrap justify-center gap-2">
      <Button variant="outline" size="sm" onClick={() => toast("Draft saved")}>
        Default
      </Button>
      <Button
        variant="outline"
        size="sm"
        onClick={() => toast.success("Payment received")}
      >
        Success
      </Button>
      <Button
        variant="outline"
        size="sm"
        onClick={() =>
          toast.error("Couldn't upload photo", {
            description: "The file is larger than 10 MB.",
          })
        }
      >
        Error
      </Button>
      <Button
        variant="outline"
        size="sm"
        onClick={() => toast.warning("Storage almost full")}
      >
        Warning
      </Button>
      <Button
        variant="outline"
        size="sm"
        onClick={() => toast.info("A new version is available")}
      >
        Info
      </Button>
    </div>
  )
}

Promise

toast.promise はスピナーを表示し、その後その場で成功またはエラーの toast に変わり、アイコンは切り替わるときにポンと現れます。

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

let attempt = 0

function deploy() {
  attempt += 1
  const fails = attempt % 2 === 0
  return new Promise<{ url: string }>((resolve, reject) =>
    setTimeout(
      () =>
        fails
          ? reject(new Error("Build failed"))
          : resolve({ url: "hextaui.com" }),
      1800
    )
  )
}

export function ToastPromise() {
  return (
    <Button
      variant="outline"
      onClick={() =>
        toast.promise(deploy(), {
          loading: "Deploying…",
          success: (data) => ({
            title: "Deployed",
            description: `Live at ${data.url}`,
          }),
          error: (error) => ({
            title: "Deploy failed",
            description: error instanceof Error ? error.message : "Try again.",
          }),
        })
      }
    >
      Deploy (fails every other time)
    </Button>
  )
}

アクション

Undo のようなボタンには action を渡します。クリックすると toast も閉じます。

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ToastAction() {
  const [archived, setArchived] = React.useState(0)

  return (
    <div className="flex flex-col items-center gap-3">
      <Button
        variant="outline"
        onClick={() => {
          setArchived((count) => count + 1)
          toast("Conversation archived", {
            action: {
              label: "Undo",
              onClick: () => setArchived((count) => count - 1),
            },
          })
        }}
      >
        Archive
      </Button>
      <p className="text-sm text-muted-foreground tabular-nums">
        {archived} archived
      </p>
    </div>
  )
}

その場で更新

toast.loading の id を保持し、toast.update でタイプも含めて変更します。

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ToastUpdate() {
  return (
    <Button
      variant="outline"
      onClick={() => {
        const id = toast.loading("Uploading 3 files…")
        setTimeout(() => toast.update(id, { title: "Uploading 2 of 3…" }), 900)
        setTimeout(
          () =>
            toast.update(id, {
              type: "success",
              title: "Upload complete",
              description: "3 files added to Photos.",
            }),
          1800
        )
      }}
    >
      Upload files
    </Button>
  )
}

重複なし

toast に id を付けると、再度呼び出したときにコピーを積み重ねる代わりに、既存のものが更新されます。

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ToastDedupe() {
  return (
    <Button
      variant="outline"
      onClick={() =>
        toast.info("You're offline", {
          id: "offline",
          description: "Changes will sync when you reconnect.",
        })
      }
    >
      Go offline (click twice)
    </Button>
  )
}
キーアクション
F6フォーカスを toast の中に移し、扇状に広げます。
Tabtoast のアクションと閉じるボタンの間を移動します。
Escフォーカスされている toast を閉じます。
  • toast は控えめに読み上げられ、toast.error はすぐに読み上げられます。
  • ポインターまたはフォーカスが toast 上にある間はタイマーが一時停止するため、カウントダウンと競う必要がありません。
  • 閉じるボタンはホバーとフォーカスで表示され、タッチスクリーンでは常に表示されます。
  • 視差効果の軽減が有効な場合、toast はスライドせずにフェードします。
プロパティ型デフォルト
positionスマートフォンでは常に全幅を使います。
"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right""bottom-right"
limit同時に表示される toast の数。古いものはフェードアウトします。
number3
timeout画面に表示される既定の時間(ms)。
number5000
属性説明
data-slot="toaster"ビューポート。data-position を持ちます。
data-slot="toast"各 toast。data-type、data-expanded、data-swiping を持ちます。
プロパティ型デフォルト
description
ReactNode–
action
{ label: ReactNode; onClick?: (event) => void }–
id重複させず更新するために再利用します。
string–
timeoutデフォルトは Toaster のタイムアウトです。長いメッセージは、毎分約250語を目安に、より長く表示されます。
number–
priority
"low" | "high""low"
onClose
() => void–
onRemove
() => void–

toast.success、toast.error、toast.warning、toast.info、toast.loading、toast.promise、toast.update、toast.dismiss もあります。それぞれ toast の id を返すか、受け取ります。

使用しているブロック

Toast の上に構築されるブロック。