Toast Stack
A capped queue of toasts sharing one live region.
6 個のフレームワーク上級
A transient, auto-dismissing confirmation announced politely.
<!--
The live region is part of the page shell, not the toast. It ships empty and
stays mounted; JS appends the toast INTO it. A role="status" element that is
inserted already-populated is usually not announced at all - screen readers
watch mounted regions for mutations.
role="status" is polite on purpose: a toast interrupting someone mid-sentence
to say "Saved" is a bug, not a feature.
-->
<div class="toast-region" role="status" aria-live="polite"></div>
<template id="toast-template">
<div class="toast">
<svg class="toast__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.7-9.3a1 1 0 0 0-1.4-1.4L9 10.6 7.7 9.3a1 1 0 0 0-1.4 1.4l2 2a1 1 0 0 0 1.4 0l4-4Z" />
</svg>
<div class="toast__body">
<p class="toast__title"></p>
<p class="toast__message"></p>
</div>
<button class="toast__close" type="button" aria-label="Dismiss">
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M6.3 6.3a1 1 0 0 1 1.4 0L10 8.6l2.3-2.3a1 1 0 1 1 1.4 1.4L11.4 10l2.3 2.3a1 1 0 0 1-1.4 1.4L10 11.4l-2.3 2.3a1 1 0 0 1-1.4-1.4L8.6 10 6.3 7.7a1 1 0 0 1 0-1.4Z" />
</svg>
</button>
</div>
</template>
<script>
const region = document.querySelector('.toast-region');
const template = document.querySelector('#toast-template');
function showToast(title, message, duration = 5000) {
const toast = template.content.firstElementChild.cloneNode(true);
toast.querySelector('.toast__title').textContent = title;
toast.querySelector('.toast__message').textContent = message;
const remove = () => toast.remove();
toast.querySelector('.toast__close').addEventListener('click', remove);
// Appending into the already-mounted region is what triggers the
// announcement.
region.append(toast);
setTimeout(remove, duration);
}
</script>| Prop | 型 | デフォルト | 説明 |
|---|---|---|---|
title必須 | string | - | カードの見出しテキスト。 |
message | string | - | 通知の本文。 |
duration | number | 5 | 自動的に閉じるまでの時間(秒)。0 の場合は閉じません。 |
onDismiss | () => void | - | ユーザーが通知を閉じたときに呼ばれます。 |
dismissLabel | string | 'Dismiss' | 閉じるボタンのアクセシブルな名前。 |
className | string | - | ルート要素にマージされる追加クラス。 |
Keep the region mounted and empty in your app shell and push toasts into it - a role="status" element populated in the same tick it mounts is usually never announced. Auto-dismiss is a convenience, not a delivery mechanism: anything the user must act on belongs in an alert that stays put. Five seconds is the floor for a short string; scale it up with the length of the message, and pause the timer on hover and focus so a toast can never expire while someone is reaching for its button.