Toast
תור של הודעות קצרות מועד.
- דפדפנים
- Chrome 114+Firefox 125+Safari 17+
- שכבה
- 1
- גודל חבילה דחוסה
- 2.87 kB
- מגבלת פריסה כפויה
- 0 ms
- מגבלת Axe
- 0
- תואם SSR
- כן
- חוזה מפורסם
- סביבת בדיקות
מגרש ניסויים
"use client";
import { Toast, useToast } from "@gunkin/uiify";
function ShowToast() {
const { toast } = useToast();
return (
<button className="" type="button" onClick={() => toast({ title: "Saved" })}>
Save
</button>
);
}
export default function Example() {
return (
<Toast.Provider>
<ShowToast />
<Toast.Viewport className="" />
</Toast.Provider>
);
}/* Toast — a fixed viewport stacking cards in the corner, promoted to the top
layer via [popover]. inset: auto overrides the UA popover default of
inset: 0 so the corner offsets below can apply; the top-layer stack is
ordered by show order, not z-index, so no manual z-index is needed. Cards
use `data-part="item"`. Cards enter, leave, and restack through React view
transitions (view-transition-class `uiify-toast`) with the shared presence
motion; the snapshots hang off the root, so they read root tokens only. */
@layer components {
[data-uiify-toast] [data-part="viewport"]:where(:not([popover]), :popover-open),
[data-uiify-toast][data-part="viewport"]:where(:not([popover]), :popover-open) {
display: flex;
}
[data-uiify-toast] [data-part="viewport"],
[data-uiify-toast][data-part="viewport"] {
position: fixed;
inset: auto;
inset-block-end: var(--space-lg);
inset-inline-end: var(--space-lg);
flex-direction: column;
gap: var(--space-sm);
inline-size: min(24rem, calc(100vw - 2 * var(--space-lg)));
margin: 0;
padding: 0;
/* Cancels the UA popover default (`border: solid` + Canvas background) —
the viewport is a transparent stacking container; cards carry their
own border and background. */
border: none;
background: none;
list-style: none;
}
[data-uiify-toast] [data-part="item"],
[data-uiify-toast][data-part="viewport"] [data-part="item"] {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-md) var(--space-lg);
border: var(--border-width) solid var(--border);
border-radius: var(--radius-lg);
background-color: var(--popover);
color: var(--popover-foreground);
box-shadow: var(--shadow-popover);
margin: 0;
min-inline-size: 0;
}
[data-uiify-toast] [data-part="close"] {
align-self: flex-end;
min-block-size: 30px;
padding-block: 0;
padding-inline: var(--space-sm);
border: 0;
border-radius: var(--radius-md);
background: transparent;
color: var(--popover-foreground);
font: inherit;
cursor: pointer;
}
[data-uiify-toast] [data-part="close"]:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
[data-uiify-toast] [data-part="close"]:hover {
background-color: var(--accent);
color: var(--accent-foreground);
}
}
@media (prefers-reduced-motion: no-preference) {
::view-transition-group(.uiify-toast) {
animation-duration: var(--duration-fast);
animation-timing-function: var(--ease-out);
}
::view-transition-new(.uiify-toast):only-child {
animation: uiify-presence-in var(--duration-fast) var(--ease-out) both;
}
::view-transition-old(.uiify-toast):only-child {
animation: uiify-presence-out var(--duration-fast) var(--ease-out) both;
}
}
@keyframes uiify-presence-in {
from {
opacity: 0;
scale: var(--presence-scale);
}
}
@keyframes uiify-presence-out {
to {
opacity: 0;
scale: var(--presence-scale);
}
}
}"use client";
import { Toast, useToast } from "@gunkin/uiify";
function ShowToast() {
const { toast } = useToast();
return (
<button
className={
"relative isolate inline-flex items-center justify-center gap-1.5 min-h-10 min-w-10 px-5 py-px border-[lengt" +
"h:var(--border-width)] border-solid border-transparent rounded-full bg-clip-padding text-base font-medium l" +
"eading-6 no-underline cursor-pointer [transition:var(--transition-colors)] focus-visible:[outline:none] foc" +
"us-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_20%,_transparent)] disabled:" +
"opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed [&:is(" +
"[data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [&:is" +
"([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [&:" +
"is([data-selected],[aria-pressed=true],[aria-current=page])]:border-transparent [&:is([data-selected],[aria" +
"-pressed=true],[aria-current=page])]:bg-primary [&:is([data-selected],[aria-pressed=true],[aria-current=pag" +
"e])]:text-primary-foreground [:checked+&]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [:checked+&]:[--uiify" +
"-button-wash:rgb(255_255_255_/_15%)] [:checked+&]:border-transparent [:checked+&]:bg-primary [:checked+&]:t" +
"ext-primary-foreground [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[&:is([data-selected],[aria-pres" +
"sed=true],[aria-current=page]):hover:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_" +
"var(--primary)_88%,_var(--primary-foreground))] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[:check" +
"ed:not(:disabled)+&:hover]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foregrou" +
"nd))] bg-foreground text-background [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:hover:[&:not(:disab" +
"led,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_90%,_var(--background))] acti" +
"ve:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_80%,_var(--ba" +
"ckground))]"
}
type="button"
onClick={() => toast({ title: "Saved" })}
>
Save
</button>
);
}
export default function Example() {
return (
<Toast.Provider>
<ShowToast />
<Toast.Viewport
className="
fixed [inset:auto] [inset-block-end:var(--space-lg)] [inset-inline-end:var(--space-lg)] flex-col gap-sm
[inline-size:min(24rem,calc(100vw_-_2_*_var(--space-lg)))] m-0 p-0 border-0 border-none bg-transparent
list-none [&:where(:not([popover]),:popover-open)]:flex [&_[data-part=item]]:flex
[&_[data-part=item]]:flex-col [&_[data-part=item]]:gap-xs
[&_[data-part=item]]:[padding:var(--space-md)_var(--space-lg)]
[&_[data-part=item]]:border-[length:var(--border-width)] [&_[data-part=item]]:border-solid
[&_[data-part=item]]:border-border [&_[data-part=item]]:rounded-lg [&_[data-part=item]]:bg-popover
[&_[data-part=item]]:text-popover-foreground [&_[data-part=item]]:shadow-popover [&_[data-part=item]]:m-0
[&_[data-part=item]]:[min-inline-size:0] [&_[data-part=close]]:self-end
[&_[data-part=close]]:[min-block-size:30px] [&_[data-part=close]]:py-0 [&_[data-part=close]]:px-sm
[&_[data-part=close]]:border-0 [&_[data-part=close]]:border-none [&_[data-part=close]]:rounded-md
[&_[data-part=close]]:bg-transparent [&_[data-part=close]]:text-popover-foreground
[&_[data-part=close]]:cursor-pointer [&_[data-part=close]:focus-visible]:outline-2
[&_[data-part=close]:focus-visible]:outline-ring [&_[data-part=close]:focus-visible]:outline-offset-2
[@media_(hover:_hover)_and_(pointer:_fine)]:[&_[data-part=close]:hover]:bg-accent
[@media_(hover:_hover)_and_(pointer:_fine)]:[&_[data-part=close]:hover]:text-accent-foreground
"
/>
</Toast.Provider>
);
}API
Toast.Provider
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
limit | number | 3 | המספר המרבי של הודעות זמניות הנשמרות בתור; הישנות יותר מוסרות. |
slotProps | ToastProviderSlotProps | — | מאפיינים לאלמנטים של האזורים החיים המנומסים והנחרצים. |
children | ReactNode | — | העץ שיכול לקרוא ל-useToast ולהציג אזור תצוגה. |
Toast.Viewport
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
aria-label | string | — | שם נגיש לאזור המכיל את ההודעות הזמניות שבתור. |
className | string | — | המחלקה המוחלת על אלמנט אזור התצוגה. |
popover | "manual" | — | מוגדר על ידי אזור התצוגה החי בצד הלקוח כדי שהתור המוצג יהיה בשכבה העליונה; מעטפת השרת משאירה אותו ללא ערך. |
ref | Ref<HTMLElement> | — | ref לאלמנט אזור התצוגה. |
slotProps | ToastViewportSlotProps | — | מאפיינים לכרטיסי הודעות זמניות ולתוכן שהם יוצרים; ניתן למקד משבצות חוזרות לפי מזהה הודעה. |
children | ReactNode | — | תוכן נוסף המוצג בתוך אזור התצוגה לצד ההודעות הזמניות שבתור. |
Toast.Root
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על כרטיס ההודעה הזמנית. |
style | CSSProperties | — | סגנונות מוטבעים המוחלים על כרטיס ההודעה הזמנית. |
ref | Ref<HTMLDivElement> | — | ref לאלמנט כרטיס ההודעה הזמנית. |
slotProps | ToastRootSlotProps | — | מאפיינים לכרטיסי הודעות זמניות ולתוכן שהם יוצרים; ניתן למקד משבצות חוזרות לפי מזהה הודעה. |
toast* | ToastRecord | — | הרשומה מהתור להצגה, עם id, כותרת, תיאור, פעולה, משך ועדיפות לאחר קביעת ערכיהם. |
Toast.Title
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על אלמנט הכותרת. |
children | ReactNode | — | תוכן הכותרת. |
Toast.Description
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על אלמנט התיאור. |
children | ReactNode | — | תוכן התיאור. |
Toast.Action
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על כפתור הפעולה. |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | נקראת בלחיצה על כפתור הפעולה. |
children | ReactNode | — | תוכן כפתור הפעולה. |
Toast.Close
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על כפתור הסגירה. |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | נקראת בלחיצה על כפתור הסגירה. |
children | ReactNode | — | תוכן כפתור הסגירה. |
useToast().toast(input)
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
title | ReactNode | — | שורת הכותרת של ההודעה הזמנית. |
description | ReactNode | — | שורה משלימה מתחת לכותרת. |
action | { label: ReactNode; onClick: () => void } | — | תווית ומטפל אירוע לכפתור פעולה יחיד בהודעה הזמנית. |
duration | number | 4000 | מספר אלפיות השנייה לפני שההודעה הזמנית נסגרת מעצמה; אפס או פחות משאירים אותה עד לסגירה מפורשת. |
priority | "polite" | "assertive" | "polite" | האזור החי שיכריז על ההודעה הזמנית. |
id | string | — | מזהה ההודעה הזמנית; נוצר אוטומטית כשהוא מושמט. |
מקלדת
| מקש | פעולה |
|---|---|
| Tab | מיקוד כפתורי פעולה בתוך ההודעה |
| Escape | סגירה כאשר ניתן לסגור |
נגישות
הכרזות polite/assertive באזור חי; הוספה לתור אינה מזיזה את המיקוד, וריחוף או מיקוד משהים סגירה אוטומטית.
נקודות חיבור לעיצוב
data-statedata-part="item"data-part="title"data-part="description"data-part="action"data-part="close"