Customize
Styling and theming
Four levels, pick the one that fits:
- CSS variables — colours, sizes, radii, the stack's spacing.
classNames— your own classes on every part, per toaster or per toast.iconsandstrings— your own SVG and your own words.render— draw the whole toast yourself; timing, stacking and swiping still apply.
Stylesheets
import '@devix-labs/toast/styles.css'; // plain
import '@devix-labs/toast/styles.layer.css'; // the same, inside @layer devix
The layered build loses to any unlayered rule of yours, so app styles win without !important.
Variables
.dxt {
--dxt-width: 356px;
--dxt-gap: 10px; /* between toasts when the stack is open */
--dxt-inset: 16px; /* from the edge of the screen */
--dxt-radius: 10px;
--dxt-font-size: 13.5px;
--dxt-title-weight: 500;
--dxt-padding: 12px 14px;
--dxt-collapse: 14px; /* how far a tucked-away toast peeks out */
--dxt-collapse-scale: 0.045;
--dxt-bg: #fff;
--dxt-text: #18181b;
--dxt-muted: #71717a;
--dxt-border: #e4e4e7;
--dxt-shadow: 0 10px 30px rgb(17 17 28 / .12);
--dxt-success: #16a34a;
--dxt-error: #dc2626;
--dxt-warning: #d97706;
--dxt-info: #2563eb;
--dxt-action-bg: #18181b;
--dxt-action-text: #fff;
--dxt-progress: currentColor;
}
Dark mode follows the page (.dark, data-theme, data-bs-theme, or the real background colour) and
re-reads it when a theme toggle flips. Force it with theme: 'dark', or write
.dxt[data-theme='dark'] { … }.
Coloured toasts, the "rich colours" look
.dxt-toast[data-type='success'] { background: #f0fdf4; border-color: #bbf7d0; color: #14532d; }
.dxt-toast[data-type='error'] { background: #fef2f2; border-color: #fecaca; color: #7f1d1d; }
.dxt[data-theme='dark'] .dxt-toast[data-type='success'] { background: #052e1a; border-color: #14532d; color: #dcfce7; }
Tailwind on every part
configure({
classNames: {
toast: 'rounded-xl border-zinc-200 shadow-lg',
title: 'text-sm font-medium',
description: 'text-xs text-zinc-500',
action: 'bg-indigo-600 text-white rounded-md',
},
});
toast('One-off', { classNames: { toast: 'ring-2 ring-indigo-500' } });
Your own markup
toast.custom((node, { dismiss }) => {
const avatar = Object.assign(document.createElement('img'), { src: user.avatar, className: 'size-8 rounded-full' });
const text = Object.assign(document.createElement('p'), { textContent: `${user.name} joined` });
const button = Object.assign(document.createElement('button'), { textContent: 'Say hi' });
button.onclick = () => { greet(user); dismiss(); };
node.append(avatar, text, button);
}, { duration: 8000 });
The node you fill is the toast itself, so it keeps the stack position, the swipe, the pause-on-hover and the dismiss timing.
Positions and stacks
Six positions, set per toaster or per toast. For two independent stacks — say, app messages bottom-right and upload progress top-left — make a second toaster:
import { createToaster } from '@devix-labs/toast';
const uploads = createToaster({ position: 'top-left', max: 5 });
uploads.loading('Uploading 3 files…');
Updated 15 Sep 2026