@xsolla/xui-toast
v0.183.0
Published
A cross-platform toast notification system matching the base Figma toast. Use it for short, non-blocking feedback with a title, optional description, optional action, and automatic or manual dismissal.
Readme
Toast
A cross-platform toast notification system matching the base Figma toast. Use it for short, non-blocking feedback with a title, optional description, optional action, and automatic or manual dismissal.
A toast is a short, non-blocking message that appears temporarily to inform the user about the result of an action or a change in system state. It appears as a compact bar that slides in from the top of the screen, stays briefly, then dismisses automatically — or can be dismissed manually.
When to use
- To confirm that an action was completed successfully (e.g. "Profile updated")
- To notify the user of a background event they didn't directly trigger (e.g. "New rewards available")
- To surface a non-critical warning that doesn't block the user from continuing
- To inform about an error that occurred in the background (e.g. "Connection lost")
When not to use
For critical errors that require the user to take action before continuing — use a modal or inline error instead
For information that the user needs to refer back to — toasts disappear and can't be recalled
- For complex messages with multiple actions — keep it to one optional CTA at most
- As a substitute for form validation errors — those belong inline next to the relevant field
Content guidelines
Title should be short and specific — 1 to 5 words: "Profile saved", "Connection lost", "Reward claimed"
Subtitle is optional — use it to add one line of supporting context, not to repeat the title
Button label should be a clear verb: "Undo", "Retry", "View" — not "OK" or "Click here"
- Avoid exclamation marks or dramatic language — keep the tone calm and factual
- Match the type to the message: use Alert only for errors, Warning for caution, Success for positive outcomes, Neutral for informational messages
Behaviour guidelines
Toasts appear at the top of the viewport, offset from the status bar or navigation
They auto-dismiss after a set duration (typically 3–5 seconds) — the exact timing is set at the product layer
When Button=False, a close (×) icon is shown — tapping it dismisses the toast immediately
When Button=True, the action button replaces the close icon — the toast can be dismissed by tapping the button or waiting for auto-dismiss
- Multiple toasts stack in a ToastGroup — see below
- Toasts do not block interaction with the rest of the screen
Accessibility
Use role="status" for Neutral and Success toasts — screen readers announce them without interrupting the user
- Use role="alert" for Warning and Alert toasts — these are announced immediately
- The close button must have aria-label="Dismiss notification"
- Do not rely on color alone to convey the type — the icon and text must also communicate it
Installation
npm install @xsolla/xui-toastImports
import {
Toast,
ToastProvider,
ToastGroup,
ToastContext,
useToast,
type ToastProps,
type ToastOptions,
type ToastType,
type ToastPosition,
type ToastAlign,
type UseToastReturn,
} from "@xsolla/xui-toast";Quick start
Wrap your app with ToastProvider, then call useToast from any descendant.
import * as React from "react";
import { XUIProvider } from "@xsolla/xui-core";
import { ToastProvider, useToast } from "@xsolla/xui-toast";
function SaveButton() {
const toast = useToast();
return (
<button onClick={() => toast.success({ title: "Saved successfully" })}>
Save
</button>
);
}
export default function App() {
return (
<XUIProvider initialMode="dark">
<ToastProvider>
<SaveButton />
</ToastProvider>
</XUIProvider>
);
}React Native: ensure the root container under
ToastProviderhasflex: 1so absolute-positioned toasts have a reference height.
API Reference
<ToastProvider>
Root provider. Manages toast state, auto-dismiss timers, and renders the ToastGroup.
| Prop | Type | Default | Description |
| ----------------- | ------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
| testID | string | - | Test ID for testing frameworks. On web this renders as data-testid; on React Native it renders as testID. |
| children | ReactNode | - | Application content. |
| position | "top" \| "bottom" | "top" | Vertical anchor of the toast container. |
| align | "left" \| "center" \| "right" | "center" | Horizontal alignment of toasts within the container. |
| defaultDuration | number | 5000 | Default auto-dismiss duration in ms. Set 0 to disable auto-dismiss globally. |
| maxWidth | number | - | Maximum width in px of the toast stack. |
<Toast>
The individual toast cell. Used internally by ToastGroup, but can be rendered standalone for static display.
| Prop | Type | Default | Description |
| ----------------- | ------------------------------------------------ | ----------- | ------------------------------------------------------------------ |
| id | string | - | Required unique identifier. |
| type | "alert" \| "success" \| "neutral" \| "warning" | "neutral" | Visual and accessibility type. |
| title | string | - | Short primary text, ideally 1 to 5 words. |
| description | string | - | Optional supporting text. |
| icon | boolean \| ReactNode | true | Show the default icon, hide it with false, or pass a custom one. |
| action | ReactElement | - | Optional action element, typically a FlexButton. |
| showCloseButton | boolean | true | Show the trailing dismiss control when onClose is provided. |
| progress | boolean | false | Show a bottom countdown strip when duration is positive; sticky toasts keep a static strip. |
| duration | number | - | Auto-dismiss duration in ms. 0 or omitted = no auto-dismiss. |
| onClose | () => void | - | Close handler. Required for the close button to render. |
Inherits ThemeOverrideProps (themeMode, themeProductContext).
<ToastGroup>
Renders the stack of visible toasts. On web uses ReactDOM.createPortal to escape stacking contexts; on React Native uses absolute positioning.
| Prop | Type | Default | Description |
| ----------- | ------------------------------- | ---------- | --------------------------- |
| toasts | ToastData[] | - | Toasts to render. |
| position | "top" \| "bottom" | "top" | Vertical anchor. |
| align | "left" \| "center" \| "right" | "center" | Horizontal alignment. |
| maxWidth | number | - | Maximum width in px. |
| onDismiss | (id: string) => void | - | Dismiss callback per toast. |
Inherits ThemeOverrideProps.
useToast()
Hook that returns toast helpers. Throws if called outside a ToastProvider.
| Method | Signature | Description |
| ------------ | ------------------------------------------------- | ----------------------------------------------------- |
| toast | (options: ToastOptions) => string | Show a toast with full options. Returns the toast ID. |
| alert | (options: Omit<ToastOptions, "type">) => string | Show an alert toast. |
| success | (options: Omit<ToastOptions, "type">) => string | Show a success toast. |
| neutral | (options: Omit<ToastOptions, "type">) => string | Show a neutral toast. |
| warning | (options: Omit<ToastOptions, "type">) => string | Show a warning toast. |
| dismiss | (id: string) => void | Dismiss a specific toast by ID. |
| dismissAll | () => void | Dismiss all visible toasts. |
ToastOptions
| Property | Type | Default | Description |
| ----------------- | ------------------------------------------------ | ---------------------------- | ------------------------------------------------------------------ |
| type | "alert" \| "success" \| "neutral" \| "warning" | "neutral" | Visual and accessibility type. |
| title | string | - | Short primary text. |
| description | string | - | Optional supporting text. |
| icon | boolean \| ReactNode | true | Show, hide, or override the icon. |
| action | ReactElement | - | Optional action element. |
| showCloseButton | boolean | true | Show the close button when the toast is dismissible. |
| progress | boolean | false | Show a bottom countdown strip when duration is positive; sticky toasts keep a static strip. |
| duration | number | provider's defaultDuration | Auto-dismiss duration. 0 keeps the toast until dismissed manually. |
ToastData
Internal shape exposed via ToastContext.toasts.
| Property | Type | Description |
| ------------- | ----------- | -------------------------------------------- |
| id | string | Unique identifier generated by the provider. |
| type | ToastType | Toast type. |
| title | string | Primary text. |
| description | string | Supporting text. |
| duration | number | Auto-dismiss duration. |
ToastContext
React context with { toasts, addToast, dismissToast, dismissAllToasts }. Typically consumed via useToast; available for advanced use cases:
import { useContext } from "react";
import { ToastContext } from "@xsolla/xui-toast";
function ActiveCount() {
const ctx = useContext(ToastContext);
if (!ctx) throw new Error("Must be within ToastProvider");
return <span>Active toasts: {ctx.toasts.length}</span>;
}Examples
Types
import * as React from "react";
import { useToast } from "@xsolla/xui-toast";
export default function Types() {
const toast = useToast();
return (
<div style={{ display: "flex", gap: 8 }}>
<button onClick={() => toast.neutral({ title: "Reward claimed" })}>
Neutral
</button>
<button onClick={() => toast.success({ title: "Quest activated" })}>
Success
</button>
<button onClick={() => toast.warning({ title: "Session expires soon" })}>
Warning
</button>
<button onClick={() => toast.alert({ title: "Connection lost" })}>
Alert
</button>
</div>
);
}Standalone Toast With Action
import * as React from "react";
import { FlexButton } from "@xsolla/xui-button";
import { Toast } from "@xsolla/xui-toast";
export default function Standalone() {
return (
<Toast
id="retry"
type="alert"
title="Connection lost"
description="Check your network and try again"
action={<FlexButton>Retry</FlexButton>}
progress
duration={5000}
onClose={() => {}}
/>
);
}Custom duration
import * as React from "react";
import { useToast } from "@xsolla/xui-toast";
export default function Duration() {
const toast = useToast();
return (
<button
onClick={() =>
toast.toast({
type: "neutral",
title: "Manual dismiss",
duration: 0,
})
}
>
Show sticky toast
</button>
);
}Position and alignment
import * as React from "react";
import { ToastProvider, useToast } from "@xsolla/xui-toast";
function Trigger() {
const toast = useToast();
return (
<button onClick={() => toast.neutral({ title: "Bottom-right toast" })}>
Show
</button>
);
}
export default function BottomRight() {
return (
<ToastProvider position="bottom" align="right" maxWidth={440}>
<Trigger />
</ToastProvider>
);
}Platform support
| Aspect | Web | React Native |
| -------------- | ------------------------------------------ | --------------------------------- |
| Rendering | ReactDOM.createPortal to document.body | Absolute-positioned Box in tree |
| Event handlers | onClick | onPress |
| Root container | Any element | Must have flex: 1 |
Accessibility
- Neutral and success toasts render with
role="status"and polite announcements. - Warning and alert toasts render with
role="alert"and assertive announcements. - The close button has
aria-label="Dismiss notification". - Do not rely on color alone; the icon and text also communicate the type.
Troubleshooting
- "useToast must be used within a ToastProvider" - ensure the calling component is a descendant of
ToastProvider. - Toasts hidden on React Native - wrap content in
<View style={{ flex: 1 }}>insideToastProvider. - Toasts appear behind a modal (web) -
ToastGroupusesz-index: 9999. PlaceToastProviderabove the modal in the tree, or adjust z-index. - Auto-dismiss not working -
duration: 0disables auto-dismiss; check both per-toast and provider defaults.
