Everything the library does, on one page. The same reference lives in the README.
npm install react-compact-toastMount the container once, near the root of your app, then call toast() from anywhere. The stylesheet is injected automatically; there is nothing else to import.
import { ToastContainer, toast } from 'react-compact-toast';
export default function App() {
return (
<>
<button onClick={() => toast.success('Saved')}>Save</button>
<ToastContainer />
</>
);
}toast('Copied to clipboard');
toast('Copied', { position: 'topRight', autoClose: 5000 });
toast({ text: 'Copied', icon: '📋' });
toast.success('Saved');
toast.error('Could not save');
toast.info('A new version is available');
toast.warning('Your session expires soon');
toast.loading('Uploading…'); // stays until you dismiss or update itEvery call returns an id you can act on later.
const id = toast.loading('Uploading…');
toast.update(id, { type: 'success', text: 'Uploaded', autoClose: 3000 });
toast.dismiss(id); // play the exit animation, then remove
toast.remove(id); // remove at once
toast.dismiss(); // all of them
toast.isActive(id); // true while it is on screen or queuedPassing your own id makes a toast idempotent, which is what you want for an action a user can repeat quickly.
const copy = () => {
navigator.clipboard.writeText(link);
toast('Link copied', { id: 'copy-link' }); // replaces itself, timer restarts
};toast.promise(saveDraft(), {
loading: 'Saving…',
success: (draft) => `Saved as “${draft.title}”`,
error: (err) => `Could not save: ${err.message}`,
});The loading toast stays open until the promise settles, then turns into a success or error toast. The original promise is returned untouched, so rejections still reach your own catch.
toast('Message archived', {
action: { label: 'Undo', onClick: () => restore() },
});A toast with an action does not close on its own, so the action stays reachable. Call event.preventDefault() inside onClick to keep it open.
toast(content, options?) takes a string, a React node, or an options object with a text key. The shorthands take the same arguments and set type.
| Name | Type | Default | Description |
|---|---|---|---|
| id | string | generated | Reuse an id to update a toast in place instead of stacking duplicates. |
| text | ReactNode | — | The message. |
| type | 'success' | 'error' | 'info' | 'warning' | 'loading' | — | Adds a built-in icon and a data-rct-type hook. |
| icon | ReactNode | from type | A custom icon. null removes it. |
| autoClose | number | false | 3000 | Milliseconds before it closes. false (or 0) keeps it open. |
| closeOnClick | boolean | true | Click, Enter, Space or Escape dismisses the toast. |
| pauseOnHover | boolean | true | Hovering pauses the timer. Focus always does. |
| closeButton | boolean | auto | Shown automatically when nothing else can dismiss the toast. |
| closeButtonLabel | string | 'Close' | Accessible name of that button. |
| action | { label, onClick } | — | A button inside the toast. Such a toast does not close on its own. |
| role | 'status' | 'alert' | 'status' | 'alert' interrupts the screen reader; type 'error' uses it by default. |
| position | ToastPosition | container's | topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight. |
| className | string | — | Your classes. Replaces the built-in look, keeps the layout. |
| unstyled | boolean | false | Drops the layout too: only positioning and animation remain. |
| style | CSSProperties | — | Inline styles for the toast. |
| onClick | (event) => void | — | Called when the toast itself is activated. |
| onClose | () => void | — | Called when the toast leaves, for any reason. |
highlightText, highlightColor, offset and containerStyle still work on a single toast but are deprecated and will be removed in 1.0.
| Name | Type | Default | Description |
|---|---|---|---|
| position | ToastPosition | 'bottomCenter' | Default position for toasts that do not set one. |
| limit | number | 6 | Toasts shown at once. Extra ones queue and appear as others leave. |
| toastOptions | Partial<ToastOptions> | — | Defaults merged under every toast. |
| newestOnTop | boolean | false | Reverses the stacking order. |
| offset | number | string | { x, y } | { x: 20, y: 30 } | Distance from the screen edges. Safe-area insets are added on top. |
| containerClassName | string | — | Classes for each position group. |
| containerStyle | CSSProperties | — | Inline styles for each position group. |
| label | string | 'Notifications' | Accessible name of the toast regions. |
| hotkey | string[] | ['altKey', 'KeyT'] | Focuses the newest toast. [] disables it. |
| pauseOnFocusLoss | boolean | true | Pauses timers while the tab is hidden or the window is blurred. |
| portal | boolean | Element | false | Renders toasts into document.body, or an element you pass. |
| injectStyles | boolean | true | Set to false to import the stylesheet yourself. |
| nonce | string | — | CSP nonce for the injected <style>. |
Render exactly one container. Two would show every toast twice, and the second one warns in development.
Set them on :root, on a wrapper, or on the toast itself.
| --rct-bg | #282828 |
| --rct-fg | #fafafa |
| --rct-radius | 16px |
| --rct-padding | 16px 24px |
| --rct-min-width | 280px |
| --rct-max-width | 320px |
| --rct-min-height | 44px |
| --rct-font-size | 14px |
| --rct-shadow | 0 0 6px rgb(0 0 0 / 0.15) |
| --rct-action-bg | rgb(128 128 128 / 0.2) |
| --rct-gap | 10px |
| --rct-gap-inline | 8px |
| --rct-offset-x | 20px |
| --rct-offset-y | 30px |
| --rct-z-index | 9999 |
| --rct-enter-duration | 0.4s |
| --rct-exit-duration | 0.3s |
| --rct-success | #22c55e |
| --rct-error | #ef4444 |
| --rct-info | #3b82f6 |
| --rct-warning | #f59e0b |
| --rct-focus-ring | currentColor |
Every part carries a data-rct-* attribute. The library's own rules are wrapped in :where(), so any single class of yours overrides them.
| [data-rct-container] | One position group |
| [data-rct-toast] | A toast |
| [data-rct-position="topRight"] | On both, the resolved position |
| [data-rct-state="entering" | "exiting"] | Animation state |
| [data-rct-type="success"] | Semantic kind |
| [data-rct-styled] | Present while the built-in look applies |
| [data-rct-base] | Present unless unstyled |
| [data-rct-text] | The message |
| [data-rct-icon] | The icon slot |
| [data-rct-action] | The action button |
| [data-rct-close] | The close button |
toast('Deployed', {
className: 'rounded-xl bg-emerald-600 px-5 py-3 text-white shadow-lg',
});className removes the built-in look but keeps the layout, so icon and text stay aligned. Add unstyled: true to remove the layout as well.
Tailwind puts utilities in @layer utilities, and unlayered CSS always wins over layered CSS. Import the stylesheet into a layer so your utilities keep the upper hand.
@import 'tailwindcss';
@import 'react-compact-toast/styles.css' layer(components);<ToastContainer injectStyles={false} />The package is a client module. Call toast() from client code only: an event handler, an effect, or a promise callback, never during render or on the server.
<ToastContainer /> may be rendered from a server layout as long as its props are serializable. This site does exactly that.
// app/layout.tsx — a server component
import { ToastContainer } from 'react-compact-toast';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<ToastContainer position="topRight" />
</body>
</html>
);
}Under a strict Content Security Policy, pass nonce, or set injectStyles={false} and import react-compact-toast/styles.css yourself.
role: alert and type: error interrupt; everything else waits politely.aria-keyshortcuts="Escape" so the shortcut is announced, and the hotkey is ignored while you are typing in a field.prefers-reduced-motion the slide is replaced by a fade.Every toast travels through eventManager, the publish–subscribe hub that lets toast() reach the container without a context or a provider. You can subscribe to it too — for analytics, logging, or a renderer of your own.
import { eventManager, ToastEvent } from 'react-compact-toast';
function log(id) {
console.log('closed', id);
}
eventManager.on(ToastEvent.Delete, log);
const off = () => eventManager.off(ToastEvent.Delete, log);Events are ToastEvent.Add, Dismiss, Delete and Update. The change is applied as soon as it is published, but callbacks run a tick later, so a subscriber never runs inside the publisher's stack. activeToastCount is read-only: it is derived from the toasts on screen rather than counted separately.
Build your own toast component on the same behaviour. Import from react-compact-toast/headless and the built-in component, its icons and the stylesheet stay out of your bundle — 3.1 kB gzipped instead of 7.0 kB.
import { useToast, useToastContainer } from 'react-compact-toast/headless';
function MyToast({ toast: record }) {
const { toastProps, dismiss } = useToast(record.id);
return (
<div {...toastProps} className="my-toast">
{record.text}
<button onClick={dismiss}>Close</button>
</div>
);
}
function MyContainer() {
const { groups } = useToastContainer({ limit: 3 });
return Array.from(groups, ([position, toasts]) => (
<div key={position} className={`my-group my-group--${position}`}>
{toasts.map((record) => (
<MyToast key={record.id} toast={record} />
))}
</div>
));
}toastProps carries the ref, ARIA attributes, keyboard handlers and hover tracking. Style the exit with [data-rct-state="exiting"] using a CSS animation or transition; the toast is removed once it finishes.