@xsolla/xui-toast
v0.150.0
Published
A cross-platform React toast notification system for displaying brief, auto-dismissing messages. Built on a provider/context architecture with a hook-based API, the Toast package supports multiple variants, configurable positioning, custom durations, cust
Readme
Toast
A cross-platform React toast notification system for displaying brief, auto-dismissing messages. Built on a provider/context architecture with a hook-based API, the Toast package supports multiple variants, configurable positioning, custom durations, custom icons, and programmatic dismiss — on both React (web) and React Native.
Installation
npm install @xsolla/xui-toast @xsolla/xui-core
# or
yarn add @xsolla/xui-toast @xsolla/xui-corePeer dependencies: react >= 16.8.0, styled-components >= 4
Architecture
The toast system uses a Provider → Context → Hook pattern:
┌─────────────────────────────────────────────────┐
│ ToastProvider │
│ ┌────────────┐ ┌───────────────────────────┐ │
│ │ ToastContext│ │ ToastGroup (portal / abs) │ │
│ │ - toasts │ │ ┌───────┐ ┌───────┐ │ │
│ │ - addToast│──▶ │ Toast │ │ Toast │ ... │ │
│ │ - dismiss │ │ └───────┘ └───────┘ │ │
│ └────────────┘ └───────────────────────────┘ │
│ ▲ │
│ │ useToast() │
│ ┌─────┴──────┐ │
│ │ Your App │ │
│ └────────────┘ │
└─────────────────────────────────────────────────┘ToastProvider— Wraps your application. Manages toast state (an array ofToastData), auto-dismiss timers, and renders theToastGroupcontainer.ToastContext— React context that exposesaddToast,dismissToast, anddismissAllToaststo descendants.useToast— Consumer hook that provides convenience methods (success,info,warning,error,dismiss,dismissAll).ToastGroup— Renders the stack of visible toasts. On web, usesReactDOM.createPortalto escape z-index stacking contexts. On React Native, uses absolute positioning.Toast— The individual notification component with icon, message, and optional close button.
Quick Start
1. Wrap your app with ToastProvider
React (Web):
import { XUIProvider } from '@xsolla/xui-core';
import { ToastProvider } from '@xsolla/xui-toast';
export default function App() {
return (
<XUIProvider initialMode="dark" initialProductContext="b2b">
<ToastProvider>
<YourApp />
</ToastProvider>
</XUIProvider>
);
}React Native:
import React from 'react';
import { View } from 'react-native';
import { XUIProvider } from '@xsolla/xui-core';
import { ToastProvider } from '@xsolla/xui-toast';
import { MainNavigator } from './navigation';
export default function App() {
return (
<XUIProvider mode="dark">
<ToastProvider position="top">
<View style={{ flex: 1 }}>
<MainNavigator />
</View>
</ToastProvider>
</XUIProvider>
);
}Important for React Native: The
ToastProviderrenders toasts using absolute positioning. Ensure your app's root container hasflex: 1so toasts position correctly relative to the screen.
2. Show toasts with useToast
import { useToast } from '@xsolla/xui-toast';
function SaveButton() {
const toast = useToast();
const handleSave = async () => {
try {
await saveData();
toast.success('Changes saved successfully');
} catch {
toast.error('Failed to save changes');
}
};
return <button onClick={handleSave}>Save</button>;
}Demo
Showing Toast Variants
Each variant conveys a different semantic meaning and displays a corresponding icon:
import { useToast } from '@xsolla/xui-toast';
export default function ToastExample() {
const toast = useToast();
return (
<div style={{ display: 'flex', gap: 8 }}>
<button onClick={() => toast.success('Quest has been activated')}>
Success
</button>
<button onClick={() => toast.info('You received 50 Xsolla Points')}>
Info
</button>
<button onClick={() => toast.warning('Your session is about to expire')}>
Warning
</button>
<button onClick={() => toast.error('Failed to save changes')}>
Error
</button>
</div>
);
}Showing Toasts (React Native)
The useToast hook works identically in React Native. Use onPress instead of onClick:
import React from 'react';
import { View } from 'react-native';
import { Button } from '@xsolla/xui-button';
import { useToast } from '@xsolla/xui-toast';
export default function ToastExample() {
const toast = useToast();
return (
<View style={{ gap: 8 }}>
<Button onPress={() => toast.success('Quest has been activated')}>
Success
</Button>
<Button onPress={() => toast.info('You received 50 Xsolla Points')}>
Info
</Button>
<Button onPress={() => toast.warning('Your session is about to expire')}>
Warning
</Button>
<Button onPress={() => toast.error('Failed to save changes')}>
Error
</Button>
</View>
);
}Toast Variants (Standalone Toast Component)
The Toast component can be used standalone outside the provider for static display or custom layouts:
import { Toast } from '@xsolla/xui-toast';
export default function ToastVariants() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, maxWidth: 400 }}>
<Toast id="1" variant="success" message="Quest has been activated" onClose={() => {}} />
<Toast id="2" variant="info" message="You received 50 Xsolla Points" onClose={() => {}} />
<Toast id="3" variant="warning" message="Your session is about to expire" onClose={() => {}} />
<Toast id="4" variant="error" message="Failed to save changes" onClose={() => {}} />
</div>
);
}Custom Duration
Control how long toasts remain visible. The default is 5000ms. Set duration: 0 to disable auto-dismiss entirely:
import { useToast } from '@xsolla/xui-toast';
export default function CustomDuration() {
const toast = useToast();
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<button onClick={() => toast.toast({ message: 'Stays for 10 seconds', duration: 10000 })}>
Long Duration (10s)
</button>
<button onClick={() => toast.toast({ message: 'Stays for 2 seconds', duration: 2000 })}>
Short Duration (2s)
</button>
<button onClick={() => toast.toast({ message: 'Dismiss me manually', duration: 0 })}>
No Auto-Dismiss
</button>
</div>
);
}You can also set a global default duration on the provider:
<ToastProvider defaultDuration={3000}>
<App />
</ToastProvider>Custom Icons
Override the default variant icon by passing a ReactNode via the icon option:
import { useToast } from '@xsolla/xui-toast';
import { Star } from '@xsolla/xui-icons';
function CustomIconExample() {
const toast = useToast();
return (
<button
onClick={() =>
toast.toast({
message: 'You earned a gold star!',
variant: 'success',
icon: <Star />,
})
}
>
Show Custom Icon Toast
</button>
);
}Dismissing Toasts Programmatically
Every toast.*() call returns a unique ID. Use it to dismiss a specific toast:
import * as React from 'react';
import { useToast } from '@xsolla/xui-toast';
export default function DismissExample() {
const toast = useToast();
const [lastToastId, setLastToastId] = React.useState<string | null>(null);
const showToast = () => {
const id = toast.info('New notification');
setLastToastId(id);
};
return (
<div style={{ display: 'flex', gap: 8 }}>
<button onClick={showToast}>Show Toast</button>
<button onClick={() => lastToastId && toast.dismiss(lastToastId)}>
Dismiss Last
</button>
<button onClick={() => toast.dismissAll()}>Dismiss All</button>
</div>
);
}Position Configuration
Toasts can be anchored to the top or bottom of the viewport:
import { ToastProvider, useToast } from '@xsolla/xui-toast';
function ToastTrigger() {
const toast = useToast();
return <button onClick={() => toast.info('Toast at the bottom!')}>Show Toast</button>;
}
export default function BottomPosition() {
return (
<ToastProvider position="bottom">
<ToastTrigger />
</ToastProvider>
);
}Multiple Toasts
Multiple toasts stack vertically in the order they are created:
import { useToast } from '@xsolla/xui-toast';
function MultipleToastsExample() {
const toast = useToast();
const showMultiple = () => {
toast.success('First toast - Success');
setTimeout(() => toast.info('Second toast - Info'), 200);
setTimeout(() => toast.warning('Third toast - Warning'), 400);
};
return <button onClick={showMultiple}>Show Multiple Toasts</button>;
}API Reference
ToastProvider
The root provider component that manages toast state and renders the toast container.
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| children | ReactNode | — | Application content. |
| position | "top" \| "bottom" | "top" | Position of the toast container on screen. |
| defaultDuration | number | 5000 | Default auto-dismiss duration in milliseconds. Set to 0 to disable auto-dismiss globally. |
| maxWidth | number | 100% | Maximum width of the toast container in pixels. If not set, toasts stretch to full viewport width. |
useToast
A hook that returns methods to show and dismiss toasts. Must be called within a ToastProvider — throws an error otherwise.
Return type: UseToastReturn
| Method | Signature | Description |
| :----- | :-------- | :---------- |
| toast | (options: ToastOptions) => string | Show a toast with full control over options. Returns the toast ID. |
| success | (message: string, options?) => string | Show a success toast with a check icon. |
| info | (message: string, options?) => string | Show an info toast with an info icon. |
| warning | (message: string, options?) => string | Show a warning toast with an alert icon. |
| error | (message: string, options?) => string | Show an error toast with an alert icon. |
| dismiss | (id: string) => void | Dismiss a specific toast by its ID. |
| dismissAll | () => void | Dismiss all visible toasts at once. |
Toast
The individual toast notification component. Used internally by ToastGroup, but can be rendered standalone for static display.
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| id | string | — | Unique identifier for the toast (required). |
| message | string | — | Toast message text (required). |
| variant | "success" \| "info" \| "warning" \| "error" | "info" | Visual variant that determines the icon color. |
| icon | ReactNode | — | Custom icon element. When omitted, a default icon for the variant is used. |
| onClose | () => void | — | Callback fired when the close button is clicked. If omitted, the close button is hidden. |
ToastOptions
Options object passed to the toast() method or as the second argument to shorthand methods.
| Property | Type | Default | Description |
| :------- | :--- | :------ | :---------- |
| message | string | — | Toast message text (required). |
| variant | "success" \| "info" \| "warning" \| "error" | "info" | Toast variant. |
| icon | ReactNode | — | Custom icon element. |
| duration | number | Provider's defaultDuration | Auto-dismiss duration in ms. Use 0 to keep the toast until manually dismissed. |
ToastData
Internal data structure for a toast instance (available via ToastContext).
| Property | Type | Description |
| :------- | :--- | :---------- |
| id | string | Unique identifier generated by the provider. |
| variant | ToastVariant | The toast variant. |
| message | string | Toast message text. |
| icon | ReactNode \| undefined | Custom icon, if provided. |
| duration | number \| undefined | Auto-dismiss duration. |
ToastContext
The React context object. Typically consumed via useToast, but available for advanced use cases:
import { useContext } from 'react';
import { ToastContext } from '@xsolla/xui-toast';
function CustomToastConsumer() {
const ctx = useContext(ToastContext);
if (!ctx) throw new Error('Must be within ToastProvider');
return <span>Active toasts: {ctx.toasts.length}</span>;
}Variant Reference
| Variant | Use Case | Default Icon | Icon Color Theme Path |
| :------ | :------- | :----------- | :-------------------- |
| success | Positive outcomes, confirmations | <Check /> | theme.colors.content.success.primary |
| info | General information, neutral messages | <AlertCircle /> | theme.colors.content.inverse |
| warning | Caution, requires user attention | <AlertCircle /> | theme.colors.content.warning.primary |
| error | Errors, failures, critical issues | <AlertCircle /> | theme.colors.content.alert.primary |
Theming
Toast uses the inverse color scheme (dark background with light text) to stand out from the application content:
Colors
theme.colors.background.inverse // Toast background
theme.colors.content.inverse // Toast text and info icon color
theme.colors.content.success.primary // Success icon color
theme.colors.content.warning.primary // Warning icon color
theme.colors.content.alert.primary // Error icon colorSizing
Toast dimensions come from theme.sizing.toast():
| Token | Value | Description |
| :---- | :---- | :---------- |
| minHeight | 64 | Minimum toast height |
| paddingHorizontal | 12 | Left/right padding |
| paddingVertical | 8 | Top/bottom padding |
| borderRadius | 4 | Corner radius |
| gap | 12 | Space between icon, text, and close button |
| iconSize | 24 | Icon dimensions |
| closeButtonSize | 24 | Close button tap target |
| closeIconSize | 20 | Close icon dimensions |
| fontSize | 16 | Message text size |
| lineHeight | 20 | Message line height |
| maxWidth | 400 | Maximum toast width (theme default; overridden by ToastProvider maxWidth prop) |
| containerPadding | 12 | Padding between toast container and screen edges |
| groupGap | 4 | Vertical gap between stacked toasts |
Platform Support
This package supports both React (web) and React Native with an identical API.
React (Web)
- Uses
ReactDOM.createPortalto render toasts at the document body level - Toasts appear above all other content regardless of z-index stacking contexts
- Works with any React web framework (Next.js, Vite, Create React App, Remix, etc.)
React Native
- Uses absolute positioning within the app container
- Toasts render within the component tree (no portal equivalent in RN)
- Works with React Navigation, Expo, and bare React Native projects
Cross-Platform Comparison
| Feature | Web | React Native |
| :------ | :-- | :----------- |
| Provider setup | ToastProvider | XUIProvider + ToastProvider |
| Hook API | useToast() | useToast() (identical) |
| Event handlers | onClick | onPress |
| Root container | Any element | Must have flex: 1 |
| Position: top | Fixed to viewport top | Absolute to container top |
| Position: bottom | Fixed to viewport bottom | Absolute to container bottom |
| Rendering | ReactDOM.createPortal into document.body | Absolute-positioned Box in tree |
React Native Example with Navigation
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { XUIProvider } from '@xsolla/xui-core';
import { ToastProvider } from '@xsolla/xui-toast';
import { RootNavigator } from './navigation';
export default function App() {
return (
<SafeAreaProvider>
<XUIProvider mode="dark">
<ToastProvider position="top">
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</ToastProvider>
</XUIProvider>
</SafeAreaProvider>
);
}Accessibility
- Each toast renders with
role="alert"andaria-live="polite"for screen reader announcements - The close button includes
aria-label="Dismiss toast"for assistive technology - Icons are decorative and do not interfere with accessibility
- Keyboard users can Tab to the close button and press Enter to dismiss
- Toast messages are limited to 2 lines (
numberOfLines={2}) for readability
Troubleshooting
"useToast must be used within a ToastProvider"
The useToast hook was called in a component that is not a descendant of ToastProvider. Ensure your component tree has a ToastProvider ancestor:
// Correct — hook is inside the provider tree
<ToastProvider>
<ComponentThatCallsUseToast />
</ToastProvider>
// Wrong — hook is outside the provider
<ComponentThatCallsUseToast />
<ToastProvider>
<OtherContent />
</ToastProvider>Toasts not visible on React Native
Make sure the container inside ToastProvider has flex: 1. Without this, the absolute-positioned toast group has no reference height:
<ToastProvider>
<View style={{ flex: 1 }}> {/* Required */}
<App />
</View>
</ToastProvider>Toasts appear behind a modal or overlay
On web, ToastGroup uses z-index: 9999. If your modal or overlay uses a higher z-index, the toasts may be hidden. Consider placing the ToastProvider above your modal provider in the tree, or adjusting z-index values.
Auto-dismiss not working
Ensure duration is not set to 0. A duration of 0 disables auto-dismiss. Check both the per-toast duration option and the provider's defaultDuration prop.
