Toast
<script setup lang="ts">
import { ref } from 'vue'
import { ToastAction, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'radix-vue'
const open = ref(false)
const eventDateRef = ref(new Date())
const timerRef = ref(0)
function oneWeekAway() {
const now = new Date()
const inOneWeek = now.setDate(now.getDate() + 7)
return new Date(inOneWeek)
}
function prettyDate(date: Date) {
return new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'short' }).format(date)
}
function handleClick() {
open.value = false
window.clearTimeout(timerRef.value)
timerRef.value = window.setTimeout(() => {
eventDateRef.value = oneWeekAway()
open.value = true
}, 100)
}
</script>
<template>
<ToastProvider>
<button
class="inline-flex items-center justify-center rounded font-medium text-[15px] px-[15px] leading-[35px] h-[35px] bg-white text-grass11 shadow-[0_2px_10px] shadow-blackA7 outline-none hover:bg-mauve3 focus:shadow-[0_0_0_2px] focus:shadow-black"
@click="handleClick"
>
Add to calendar
</button>
<ToastRoot
v-model:open="open"
class="bg-white rounded-md shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] p-[15px] grid [grid-template-areas:_'title_action'_'description_action'] grid-cols-[auto_max-content] gap-x-[15px] items-center data-[state=open]:animate-slideIn data-[state=closed]:animate-hide data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-[transform_200ms_ease-out] data-[swipe=end]:animate-swipeOut"
>
<ToastTitle class="[grid-area:_title] mb-[5px] font-medium text-slate12 text-[15px]">
Scheduled: Catch up
</ToastTitle>
<ToastDescription as-child>
<time
class="[grid-area:_description] m-0 text-slate11 text-[13px] leading-[1.3]"
:dateTime="eventDateRef.toISOString()"
>
{{ prettyDate(eventDateRef) }}
</time>
</ToastDescription>
<ToastAction
class="[grid-area:_action]"
as-child
alt-text="Goto schedule to undo"
>
<button class="inline-flex items-center justify-center rounded font-medium text-xs px-[10px] leading-[25px] h-[25px] bg-green2 text-green11 shadow-[inset_0_0_0_1px] shadow-green7 hover:shadow-[inset_0_0_0_1px] hover:shadow-green8 focus:shadow-[0_0_0_2px] focus:shadow-green8">
Undo
</button>
</ToastAction>
</ToastRoot>
<ToastViewport class="[--viewport-padding:_25px] fixed bottom-0 right-0 flex flex-col p-[var(--viewport-padding)] gap-[10px] w-[390px] max-w-[100vw] m-0 list-none z-[2147483647] outline-none" />
</ToastProvider>
</template>
- 自動的に閉じます。
- ホバー、フォーカス、ウィンドウのフォーカス喪失時に閉じることが一時停止します。
- Toastビューポートにジャンプするためのホットキーをサポートします。
- スワイプジェスチャーによる閉じ方をサポートします。
- スワイプジェスチャーアニメーション用のCSS変数を公開します。
- 制御可能または非制御可能です。
インストール
コマンドラインからコンポーネントをインストールします。
$ npm add radix-vue
構成
コンポーネントをインポートします。
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'radix-vue'
</script>
<template>
<ToastProvider>
<ToastRoot>
<ToastTitle />
<ToastDescription />
<ToastAction />
<ToastClose />
</ToastRoot>
<ToastViewport />
</ToastProvider>
</template>
APIリファレンス
プロバイダー
ToastとToastビューポートをラップするプロバイダー。通常はアプリケーションをラップします。
プロパティ | デフォルト | 型 |
---|---|---|
duration | 5000 | number 各Toastが表示されるミリ秒数。 |
label | 'Notification' | string 各Toastの作者によるローカライズされたラベル。スクリーンリーダーユーザーが中断をToastに関連付けるのに役立ちます。 |
swipeDirection | 'right' | 'right' | 'left' | 'up' | 'down' Toastを閉じるべきポインターのスワイプ方向。 |
swipeThreshold | 50 | number 閉じ動作がトリガーされる前にスワイプが通過する必要があるピクセル数。 |
ビューポート
Toastが表示される固定領域。ユーザーはホットキーを押してビューポートにジャンプできます。キーボードユーザー向けにホットキーの検出可能性を確保するのは、ユーザーの責任です。
プロパティ | デフォルト | 型 |
---|---|---|
as | 'ol' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 | |
hotkey | ['F8'] | string[] Toastビューポートにフォーカスを移動するキーボードショートカットとして使用するキー。 |
label | 'Notifications ({hotkey})' | string | ((hotkey: string) => string) ページのランドマークをナビゲートする際にスクリーンリーダーユーザーにコンテキストを提供するためのToastビューポートの作者によるローカライズされたラベル。利用可能な |
ルート
自動的に閉じられるToast。ユーザーの応答を得るために開いたままにしておくべきではありません。
プロパティ | デフォルト | 型 |
---|---|---|
as | 'li' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 | |
defaultOpen | true | boolean 最初にレンダリングされたときのダイアログの開いている状態。開いている状態を制御する必要がない場合に使用します。 |
duration | number Toastが表示されるミリ秒数。 | |
forceMount | boolean より多くの制御が必要な場合にマウントを強制するために使用します。Vueアニメーションライブラリでアニメーションを制御する場合に役立ちます。 | |
open | boolean ダイアログの制御された開いている状態。 | |
type | 'foreground' | 'foreground' | 'background' アクセシビリティのためにToastの感度を制御します。 ユーザーアクションの結果であるToastの場合は、 |
Emit | ペイロード |
---|---|
escapeKeyDown | [event: KeyboardEvent] Escapeキーが押されたときに呼び出されるイベントハンドラー。 |
pause | [] 破棄タイマーが一時停止されたときに呼び出されるイベントハンドラー。これは、ポインターがビューポート上に移動したとき、ビューポートにフォーカスが当たったとき、またはウィンドウのフォーカスが失われたときに発生します。 |
resume | [] 破棄タイマーが再開されたときに呼び出されるイベントハンドラー。これは、ポインターがビューポートから離れたとき、ビューポートのフォーカスが失われたとき、またはウィンドウにフォーカスが当たったときに発生します。 |
swipeCancel | [event: SwipeEvent] |
swipeEnd | [event: SwipeEvent] スワイプ操作の最後に呼び出されるイベントハンドラー。 |
swipeMove | [event: SwipeEvent] スワイプ操作中に呼び出されるイベントハンドラー。 |
swipeStart | [event: SwipeEvent] スワイプ操作の開始時に呼び出されるイベントハンドラー。 |
update:open | [value: boolean] 開いている状態が変更されたときに呼び出されるイベントハンドラー |
スロット (デフォルト) | ペイロード |
---|---|
open | boolean 現在の開いている状態 |
remaining | number 残りの時間 (ミリ秒) |
duration | number Toastが表示される総時間 (ミリ秒) |
データ属性 | 値 |
---|---|
[data-state] | "open" | "closed" |
[data-swipe] | "start" | "move" | "cancel" | "end" |
[data-swipe-direction] | "up" | "down" | "left" | "right" |
CSS変数 | 説明 |
---|---|
--radix-toast-swipe-move-x | 水平方向にスワイプしたときのToastのオフセット位置 |
--radix-toast-swipe-move-y | 垂直方向にスワイプしたときのToastのオフセット位置 |
--radix-toast-swipe-end-x | 水平方向にスワイプした後のToastのオフセット終了位置 |
--radix-toast-swipe-end-y | 垂直方向にスワイプした後のToastのオフセット終了位置 |
タイトル
Toastのオプションのタイトル
プロパティ | デフォルト | 型 |
---|---|---|
as | 'div' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 |
説明
Toastメッセージ。
プロパティ | デフォルト | 型 |
---|---|---|
as | 'div' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 |
アクション
無視しても安全なアクション。ユーザーが時間制限の結果として予期しない副作用のあるタスクを完了する必要がないようにするためです。
ユーザーの応答を得る必要がある場合は、代わりにToastとしてスタイル設定された"AlertDialog"をビューポートにポータルします。
プロパティ | デフォルト | 型 |
---|---|---|
altText* | string アクションを実行する代替方法の簡単な説明。スクリーンリーダーユーザーがボタンに簡単/迅速に移動できない場合のため。 | |
as | 'div' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 |
閉じる
ユーザーが期間が経過する前にToastを閉じることができるボタン。
プロパティ | デフォルト | 型 |
---|---|---|
as | 'button' | AsTag | Component このコンポーネントがレンダリングされる要素またはコンポーネント。 |
asChild | boolean 子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。 詳細については、コンポジションガイドをご覧ください。 |
例
カスタムホットキー
keycode.infoから各キーのevent.code
値を使用して、デフォルトのホットキーを上書きします。
<ToastProvider>
...
<ToastViewport :hotkey="['altKey', 'KeyT']" />
</ToastProvider>
カスタム期間
プロバイダーの値を上書きするために、Toastの期間をカスタマイズします。
<ToastRoot :duration="3000">
<ToastDescription>Saved!</ToastDescription>
</ToastRoot>
Toastの複製
ユーザーがボタンをクリックするたびにToastを表示する必要がある場合、状態を使用して同じToastの複数のインスタンスをレンダリングします(下記参照)。または、独自の命令型APIを作成するために、部分を抽象化することもできます。
<div>
<form @submit="count++">
...
<button>save</button>
</form>
<ToastRoot v-for="(_, index) in count" :key="index">
<ToastDescription>Saved!</ToastDescription>
</ToastRoot>
</div>
スワイプジェスチャーのアニメーション
--radix-toast-swipe-move-[x|y]
と--radix-toast-swipe-end-[x|y]
のCSS変数をdata-swipe="[start|move|cancel|end]"
属性と組み合わせて、閉じるジェスチャーをアニメーション化します。例を以下に示します。
<ToastProvider swipeDirection="right">
<ToastRoot class="ToastRoot">...</ToastRoot>
<ToastViewport />
</ToastProvider>
/* styles.css */
.ToastRoot[data-swipe='move'] {
transform: translateX(var(--radix-toast-swipe-move-x));
}
.ToastRoot[data-swipe='cancel'] {
transform: translateX(0);
transition: transform 200ms ease-out;
}
.ToastRoot[data-swipe='end'] {
animation: slideRight 100ms ease-out;
}
@keyframes slideRight {
from {
transform: translateX(var(--radix-toast-swipe-end-x));
}
to {
transform: translateX(100%);
}
}
アクセシビリティ
aria-live
の要件に準拠しています。
感度
type
プロパティを使用して、スクリーンリーダー向けのToastの感度を制御します。
ユーザーアクションの結果であるToastの場合は、foreground
を選択します。バックグラウンドタスクから生成されたToastにはbackground
を使用する必要があります。
フォアグラウンド
フォアグラウンドのToastはすぐにアナウンスされます。補助技術は、フォアグラウンドのToastが表示されたときに、以前にキューに入れられたメッセージをクリアすることを選択する場合があります。同時に異なるフォアグラウンドのToastを積み重ねることは避けてください。
背景
背景トーストは、次の適切な機会にアナウンスされます。例えば、スクリーンリーダーが現在の文の読み上げを終えた時などです。キューに入れられたメッセージはクリアされないため、ユーザーインタラクションへの応答としてこれらを多用すると、スクリーンリーダーユーザーにとって遅延のあるユーザーエクスペリエンスに感じられる可能性があります。
<ToastRoot type="foreground">
<ToastDescription>File removed successfully.</ToastDescription>
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
<ToastRoot type="background">
<ToastDescription>We've just released Radix 1.0.</ToastDescription>
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
代替アクション
Action
の altText
プロパティを使用して、スクリーンリーダーユーザーに対してトーストのアクションを実行する代替方法を指示します。
アプリケーション内の恒久的な場所でユーザーにアクションを実行させるように指示するか、独自のホットキーロジックを実装できます。後者を実装する場合は、foreground
タイプを使用してすぐにアナウンスし、ユーザーに十分な時間を与えるために期間を長くします。
<ToastRoot type="background">
<ToastTitle>Upgrade Available!</ToastTitle>
<ToastDescription>We've just released Radix 1.0.</ToastDescription>
<ToastAction altText="Goto account settings to upgrade">
Upgrade
</ToastAction>
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
<ToastRoot type="foreground" :duration="10000">
<ToastDescription>File removed successfully.</ToastDescription>
<ToastAction altText="Undo (Alt+U)">
Undo <kbd>Alt</kbd>+<kbd>U</kbd>
</ToastAction>
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
閉じるアイコンボタン
アイコン(またはフォントアイコン)を提供する場合は、スクリーンリーダーユーザーのために正しくラベル付けすることを忘れないでください。
<ToastRoot type="foreground">
<ToastDescription>Saved!</ToastDescription>
<ToastClose aria-label="Close">
<span aria-hidden>×</span>
</ToastClose>
</ToastRoot>
キーボード操作
キー | 説明 |
---|---|
F8 | トーストビューポートにフォーカスします。 |
Tab | フォーカスを次のフォーカス可能な要素に移動します。 |
Shift + Tab | フォーカスを前のフォーカス可能な要素に移動します。 |
Space | ToastAction または ToastClose にフォーカスがある場合、トーストを閉じます。 |
Enter | ToastAction または ToastClose にフォーカスがある場合、トーストを閉じます。 |
Esc | Toast にフォーカスがある場合、トーストを閉じます。 |
カスタムAPI
抽象的な部分
プリミティブな部分を独自のコンポーネントに抽象化することで、独自のAPIを作成します。
使用方法
<script setup lang="ts">
import Toast from './your-toast.vue'
</script>
<template>
<Toast
title="Upgrade available"
content="We've just released Radix 3.0!"
>
<button @click="handleUpgrade">
Upgrade
</button>
</Toast>
</template>
実装
// your-toast.vue
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'radix-vue'
defineProps<{
title: string
content: string
}>()
</script>
<template>
<ToastRoot>
<ToastTitle v-if="title">
{{ title }}
</ToastTitle>
<ToastDescription>{{ content }}</ToastDescription>
<ToastAction
as-child
alt-text="toast"
>
<slot />
</ToastAction>
<ToastClose aria-label="Close">
<span aria-hidden>×</span>
</ToastClose>
</ToastRoot>
</template>
命令型API
必要であれば、トーストの複製 を許可する独自の命令型APIを作成します。
使用方法
<script setup lang="ts">
import Toast from './your-toast.vue'
const savedRef = ref<InstanceType<typeof Toast>>()
</script>
<template>
<div>
<form @submit="savedRef.publish()">
...
</form>
<Toast ref="savedRef">
Saved successfully!
</Toast>
</div>
</template>
実装
// your-toast.vue
<script setup lang="ts">
import { ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'radix-vue'
import { ref } from 'vue'
const count = ref(0)
function publish() {
count.value++
}
defineExpose({
publish
})
</script>
<template>
<ToastRoot
v-for="index in count"
:key="index"
>
<ToastDescription>
<slot />
</ToastDescription>
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
</template>