Skip to content

Toast

Queue of short-lived notifications.

Browsers
Chrome 114+Firefox 125+Safari 17+
Tier
1
Bundle compressed
2.41 kB
Forced layout budget
0 ms
Axe budget
0
SSR compatible
Yes
Published contract
Test harness

Playground

Toast

Viewport

"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);
    corner-shape: squircle;
    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={
        "focus-visible:[outline:none] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ri" +
        "ng)_16%,_transparent)] [--uiify-button-rim:rgb(255_255_255_/_20%)] [--uiify-button-wash:light-dark(rgb(255_" +
        "255_255_/_15%),_rgb(255_255_255_/_30%))] relative isolate inline-flex items-center justify-center [gap:0.37" +
        "5rem] [min-block-size:44px] [min-inline-size:44px] py-0 [padding-inline:1.25rem] border-[length:var(--borde" +
        "r-width)] border-solid border-transparent rounded-[var(--radius-full)] bg-foreground bg-clip-padding text-b" +
        "ackground text-base font-[number:var(--weight-medium)] leading-6 no-underline cursor-pointer [transition:va" +
        "r(--transition-colors)] before:content-[''] before:absolute before:inset-0 before:z-[-1] before:[border-rad" +
        "ius:inherit] before:pointer-events-none after:content-[''] after:absolute after:inset-0 after:z-[-1] after:" +
        "[border-radius:inherit] after:pointer-events-none before:[background-color:var(--uiify-button-wash)] before" +
        ":[filter:blur(10px)] before:[translate:0_-50%] before:[clip-path:inset(50%_0_-50%_0_round_var(--radius-full" +
        "))] after:[padding:0.5px] after:[background-image:linear-gradient(to_bottom,_var(--uiify-button-rim),_trans" +
        "parent_75%)] after:[mask:linear-gradient(#fff_0_0)_content-box_exclude,_linear-gradient(#fff_0_0)] [&:is([d" +
        "ata-size=sm],[data-size=icon-sm])]:[min-block-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[min-in" +
        "line-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[padding-inline:0.75rem] [&:is([data-size=sm],[d" +
        "ata-size=icon-sm])]:[gap:0.25rem] [&:is([data-size=sm],[data-size=icon-sm])]:text-sm [&:is([data-size=sm],[" +
        "data-size=icon-sm])]:leading-5 [&:is([data-size=lg],[data-size=icon-lg])]:[min-block-size:56px] [&:is([data" +
        "-size=lg],[data-size=icon-lg])]:[min-inline-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[padding-" +
        "inline:1.75rem] [&:is([data-size=lg],[data-size=icon-lg])]:text-lg [&:is([data-size=lg],[data-size=icon-lg]" +
        ")]:leading-7 [&[data-size^=icon]]:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:hover:[&:not(:di" +
        "sabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_90%,_var(--background))] a" +
        "ctive:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_80%,_var(-" +
        "-background))] disabled:opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:c" +
        "ursor-not-allowed data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[ar" +
        "ia-current=page]))]:[--uiify-button-rim:light-dark(rgb(0_0_0_/_5%),_rgb(255_255_255_/_10%))] data-[variant=" +
        "secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-but" +
        "ton-wash:light-dark(rgb(255_255_255_/_20%),_rgb(255_255_255_/_5%))] data-[variant=secondary]:[&:where(:not(" +
        ":checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[background-color:color-mix(in_oklch," +
        "_var(--foreground)_10%,_transparent)] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[ar" +
        "ia-pressed=true],[aria-current=page]))]:text-foreground data-[variant=outline]:[&:where(:not(:checked+*,[da" +
        "ta-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:color-mix(in_oklch,_var(--foreg" +
        "round)_25%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=tru" +
        "e],[aria-current=page]))]:[border-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] data-[vari" +
        "ant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transpa" +
        "rent data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page" +
        "]))]:text-foreground data-[variant=outline]:before:content-none data-[variant=outline]:after:[inset:calc(-1" +
        "_*_var(--border-width))] data-[variant=outline]:after:[padding:var(--border-width)] data-[variant=outline]:" +
        "[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled" +
        ",[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant" +
        "=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent " +
        "data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:te" +
        "xt-foreground data-[variant=ghost]:before:content-none data-[variant=ghost]:after:content-none data-[varian" +
        "t=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(" +
        ":disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data" +
        "-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:ac" +
        "tive:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_26%,_transp" +
        "arent)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-curre" +
        "nt=page]))]:[--uiify-button-wash:rgb(255_255_255_/_15%)] data-[variant=destructive]:[&:where(:not(:checked+" +
        "*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-destructive data-[variant=destructive]:text" +
        "-destructive-foreground data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=t" +
        "rue],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch," +
        "_var(--destructive),_black_20%)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=outline]" +
        ":[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled" +
        ",[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-" +
        "hover:_hover)_and_(any-pointer:_fine)]:data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-" +
        "pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(i" +
        "n_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[var" +
        "iant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[" +
        "&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)" +
        "] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=destructive]:[&:where(:not(:checked+*,[" +
        "data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[backgro" +
        "und-color:color-mix(in_oklch,_var(--destructive),_black_12%)] [&:is([data-selected],[aria-pressed=true],[ar" +
        "ia-current=page])]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [&:is([data-selected],[aria-pressed=true],[a" +
        "ria-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=page])]: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+&]:text-primary-foreground [@media_(any-hov" +
        "er:_hover)_and_(any-pointer:_fine)]:[&:is([data-selected],[aria-pressed=true],[aria-current=page]):hover:no" +
        "t(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreg" +
        "round))] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[:checked:not(:disabled)+&:hover]:[background-" +
        "color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [:disabled+&]:opacity-50 [:disabl" +
        "ed+&]:cursor-not-allowed [&[hidden]]:hidden data-[variant=link]:px-0 data-[variant=link]:border-0 data-[var" +
        "iant=link]:border-current data-[variant=link]:border-none data-[variant=link]:rounded-none data-[variant=li" +
        "nk]:bg-transparent data-[variant=link]:text-primary data-[variant=link]:underline data-[variant=link]:[text" +
        "-underline-offset:0.2em] data-[variant=link]:active:px-0 data-[variant=link]:active:border-0 data-[variant=" +
        "link]:active:border-current data-[variant=link]:active:border-none data-[variant=link]:active:rounded-none " +
        "data-[variant=link]:active:bg-transparent data-[variant=link]:active:text-primary data-[variant=link]:activ" +
        "e:underline data-[variant=link]:active:[text-underline-offset:0.2em] data-[variant=link]:[min-inline-size:0" +
        "] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:px-0 [@media_(any-hover:_ho" +
        "ver)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-0 [@media_(any-hover:_hover)_and_(any-pointe" +
        "r:_fine)]:data-[variant=link]:hover:border-current [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data" +
        "-[variant=link]:hover:border-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:h" +
        "over:rounded-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:bg-transpar" +
        "ent [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:text-primary [@media_(any" +
        "-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:underline [@media_(any-hover:_hover)_and_" +
        "(any-pointer:_fine)]:data-[variant=link]:hover:[text-underline-offset:0.2em] data-[variant=link]:before:con" +
        "tent-none data-[variant=link]:after:content-none data-[variant=link]:focus-visible:[outline:2px_solid_var(-" +
        "-ring)] data-[variant=link]:focus-visible:[outline-offset:3px] [[data-uiify-toggle]>input:focus-visible+&]:" +
        "[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-toggle-" +
        "group]_[data-part=item]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(" +
        "--ring)_16%,_transparent)] [[data-uiify-modal][data-part=close]&]:border-transparent [[data-uiify-modal][da" +
        "ta-part=close]&]:[background-color:color-mix(in_oklch,_var(--foreground)_8%,_transparent)] [[data-uiify-mod" +
        "al][data-part=close]&]:text-foreground [[data-uiify-modal][data-part=close]&:hover]:[background-color:color" +
        "-mix(in_oklch,_var(--foreground)_14%,_transparent)] [[data-uiify-modal][data-part=close]&:active]:[backgrou" +
        "nd-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] [[data-uiify-pagination]_span&:not([data-" +
        "disabled])]:cursor-default [[data-uiify-input-group]>[data-part=addon]>&]:[min-inline-size:0] [[data-uiify-" +
        "input-group]>[data-part=addon]>&]:[max-inline-size:100%] [[data-uiify-input-group]>[data-part=addon]>&]:whi" +
        "tespace-normal [[data-uiify-input-group]>[data-part=addon]>&]:[overflow-wrap:anywhere] [[data-uiify-item-co" +
        "ntent]>&]:[justify-self:start]"
      }
      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]]:[corner-shape:squircle] [&_[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>
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('focus-visible:[outline:none] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [--uiify-button-rim:rgb(255_255_255_/_20%)] [--uiify-button-wash:light-dark(rgb(255_255_255_/_15%),_rgb(255_255_255_/_30%))] relative isolate inline-flex items-center justify-center [gap:0.375rem] [min-block-size:44px] [min-inline-size:44px] py-0 [padding-inline:1.25rem] border-[length:var(--border-width)] border-solid border-transparent rounded-[var(--radius-full)] bg-foreground bg-clip-padding text-background text-base font-[number:var(--weight-medium)] leading-6 no-underline cursor-pointer [transition:var(--transition-colors)] before:absolute before:inset-0 before:z-[-1] before:[border-radius:inherit] before:pointer-events-none after:absolute after:inset-0 after:z-[-1] after:[border-radius:inherit] after:pointer-events-none before:[background-color:var(--uiify-button-wash)] before:[filter:blur(10px)] before:[translate:0_-50%] before:[clip-path:inset(50%_0_-50%_0_round_var(--radius-full))] after:[padding:0.5px] after:[background-image:linear-gradient(to_bottom,_var(--uiify-button-rim),_transparent_75%)] after:[mask:linear-gradient(#fff_0_0)_content-box_exclude,_linear-gradient(#fff_0_0)] [&:is([data-size=sm],[data-size=icon-sm])]:[min-block-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[min-inline-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[padding-inline:0.75rem] [&:is([data-size=sm],[data-size=icon-sm])]:[gap:0.25rem] [&:is([data-size=sm],[data-size=icon-sm])]:text-sm [&:is([data-size=sm],[data-size=icon-sm])]:leading-5 [&:is([data-size=lg],[data-size=icon-lg])]:[min-block-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[min-inline-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[padding-inline:1.75rem] [&:is([data-size=lg],[data-size=icon-lg])]:text-lg [&:is([data-size=lg],[data-size=icon-lg])]:leading-7 [&[data-size^=icon]]:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_90%,_var(--background))] active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_80%,_var(--background))] disabled:opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:light-dark(rgb(0_0_0_/_5%),_rgb(255_255_255_/_10%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-wash:light-dark(rgb(255_255_255_/_20%),_rgb(255_255_255_/_5%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:color-mix(in_oklch,_var(--foreground)_25%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[border-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=outline]:before:content-none data-[variant=outline]:after:[inset:calc(-1_*_var(--border-width))] data-[variant=outline]:after:[padding:var(--border-width)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=ghost]:before:content-none data-[variant=ghost]:after:content-none data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_26%,_transparent)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-wash:rgb(255_255_255_/_15%)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-destructive data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--destructive),_black_20%)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--destructive),_black_12%)] [&: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=page])]: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+&]:text-primary-foreground [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[&:is([data-selected],[aria-pressed=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)]:[:checked:not(:disabled)+&:hover]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [:disabled+&]:opacity-50 [:disabled+&]:cursor-not-allowed [&[hidden]]:hidden data-[variant=link]:px-0 data-[variant=link]:border-0 data-[variant=link]:border-current data-[variant=link]:border-none data-[variant=link]:rounded-none data-[variant=link]:bg-transparent data-[variant=link]:text-primary data-[variant=link]:underline data-[variant=link]:[text-underline-offset:0.2em] data-[variant=link]:active:px-0 data-[variant=link]:active:border-0 data-[variant=link]:active:border-current data-[variant=link]:active:border-none data-[variant=link]:active:rounded-none data-[variant=link]:active:bg-transparent data-[variant=link]:active:text-primary data-[variant=link]:active:underline data-[variant=link]:active:[text-underline-offset:0.2em] data-[variant=link]:[min-inline-size:0] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-current [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:rounded-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:bg-transparent [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:text-primary [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:underline [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:[text-underline-offset:0.2em] data-[variant=link]:before:content-none data-[variant=link]:after:content-none data-[variant=link]:focus-visible:[outline:2px_solid_var(--ring)] data-[variant=link]:focus-visible:[outline-offset:3px] [[data-uiify-toggle]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-toggle-group]_[data-part=item]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-modal][data-part=close]&]:border-transparent [[data-uiify-modal][data-part=close]&]:[background-color:color-mix(in_oklch,_var(--foreground)_8%,_transparent)] [[data-uiify-modal][data-part=close]&]:text-foreground [[data-uiify-modal][data-part=close]&:hover]:[background-color:color-mix(in_oklch,_var(--foreground)_14%,_transparent)] [[data-uiify-modal][data-part=close]&:active]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] [[data-uiify-pagination]_span&:not([data-disabled])]:cursor-default [[data-uiify-input-group]>[data-part=addon]>&]:[min-inline-size:0] [[data-uiify-input-group]>[data-part=addon]>&]:[max-inline-size:100%] [[data-uiify-input-group]>[data-part=addon]>&]:whitespace-normal [[data-uiify-input-group]>[data-part=addon]>&]:[overflow-wrap:anywhere] [[data-uiify-item-content]>&]:[justify-self:start] 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]]:[corner-shape:squircle] [&_[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');

@source inline("before:content-[''] after:content-['']");

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

Toast.Provider

PropTypeDefaultDescription
limitnumber3Maximum number of toasts kept in the queue; older ones are dropped.
childrenReactNode—The tree that can call useToast and render a viewport.

Toast.Viewport

PropTypeDefaultDescription
aria-labelstring—Accessible name for the region that holds the queued toasts.
classNamestring—Class applied to the viewport element.
popover"manual"—Set by the live client viewport so the rendered queue sits in the top layer; the server shell leaves it unset.
refRef<HTMLElement>—Ref to the viewport element.
childrenReactNode—Extra content rendered inside the viewport alongside the queued toasts.

Toast.Root

PropTypeDefaultDescription
toast*ToastRecord—The queued record to render, with its resolved id, title, description, action, duration and priority.

Toast.Title

PropTypeDefaultDescription
classNamestring—Class applied to the title element.
childrenReactNode—Content of the title.

Toast.Description

PropTypeDefaultDescription
classNamestring—Class applied to the description element.
childrenReactNode—Content of the description.

Toast.Action

PropTypeDefaultDescription
classNamestring—Class applied to the action button.
onClick(event: MouseEvent<HTMLButtonElement>) => void—Called when the action button is clicked.
childrenReactNode—Content of the action button.

Toast.Close

PropTypeDefaultDescription
classNamestring—Class applied to the close button.
onClick(event: MouseEvent<HTMLButtonElement>) => void—Called when the close button is clicked.
childrenReactNode—Content of the close button.

useToast().toast(input)

PropTypeDefaultDescription
titleReactNode—Title line of the toast.
descriptionReactNode—Supporting line under the title.
action{ label: ReactNode; onClick: () => void }—Label and handler for a single action button on the toast.
durationnumber4000Milliseconds before the toast dismisses itself; zero or less keeps it until dismissed.
priority"polite" | "assertive""polite"Which live region announces the toast.
idstring—Id for the toast; generated when omitted.

Keyboard

KeyAction
TabFocus action buttons inside toast
EscapeDismiss when closable

Accessibility

Live region polite/assertive announcements; enqueue does not move focus, and hover/focus pause automatic dismissal.

Styling hooks

data-statedata-part="item"data-part="title"data-part="description"data-part="action"data-part="close"