Toast v2

Beautiful, accessible toasts with smooth animations and gesture support.

14
4
4.0s

Features

  • Composable component API

  • Smooth stacking with hover-to-expand

  • Swipe to dismiss with spring physics

  • Promise toasts for async operations

  • Works with all Tamagui animation drivers

Installation

yarn add @tamagui/toast

Optionally install Burnt  for native OS-level toasts on iOS/Android. Without it, toasts render as in-app UI on all platforms.

Quick Start

import { Toast, toast, useToasts } from '@tamagui/toast/v2'
function App() {
return (
<Toast position="bottom-right">
<Toast.Viewport>
<ToastList />
</Toast.Viewport>
<Button onPress={() => toast('Hello!')}>Show Toast</Button>
</Toast>
)
}
function ToastList() {
const { toasts } = useToasts()
return (
<>
{toasts.map((t, index) => (
<Toast.Item key={t.id} toast={t} index={index}>
<Toast.Title>{t.title}</Toast.Title>
<Toast.Description>{t.description}</Toast.Description>
<Toast.Close />
</Toast.Item>
))}
</>
)
}

Anatomy

<Toast> {/* Root - context and position */}
<Toast.Viewport> {/* Container with portal */}
<Toast.Item> {/* Individual toast with stacking/drag */}
<Toast.Title />
<Toast.Description />
<Toast.Close />
<Toast.Action />
</Toast.Item>
</Toast.Viewport>
</Toast>

API

toast()

The imperative toast function:

// Basic
toast('Hello world')
// With types
toast.success('Saved!')
toast.error('Failed')
toast.warning('Careful')
toast.info('FYI')
toast.loading('Processing...')
// With options
toast('Message', {
description: 'More details here',
duration: 5000,
})
// Dismiss
const id = toast('Hello')
toast.dismiss(id) // dismiss specific
toast.dismiss() // dismiss all

toast.promise()

For async operations:

toast.promise(saveData(), {
loading: 'Saving...',
success: 'Saved!',
error: 'Failed to save',
})

Toast (Root)

Props

  • position

    'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'

    Default: 

    'bottom-right'

    Position of the toast viewport.

  • duration

    number

    Default: 

    4000

    Default toast duration in milliseconds.

  • gap

    number

    Default: 

    14

    Gap between toasts when expanded.

  • visibleToasts

    number

    Default: 

    4

    Maximum number of visible toasts.

  • swipeDirection

    'auto' | 'left' | 'right' | 'up' | 'down'

    Default: 

    'auto'

    Swipe direction to dismiss. 'auto' detects based on position.

  • closeButton

    boolean

    Default: 

    false

    Show close button on toasts.

  • Toast.Viewport

    The portal container for toasts. Extends Stack.

    Props

  • offset

    number | { top?: number, right?: number, bottom?: number, left?: number }

    Default: 

    24

    Offset from screen edge.

  • hotkey

    string[]

    Default: 

    ['altKey', 'KeyT']

    Hotkey to focus viewport.

  • label

    string

    Default: 

    'Notifications'

    Aria label for the viewport.

  • Toast.Item

    Individual toast wrapper with stacking and drag support. Extends Stack.

    Props

  • toast (required)

    ToastT

    The toast data object.

  • index (required)

    number

    Index in the toast list (for stacking).

  • Supports render prop for custom content:

    <Toast.Item toast={t} index={i}>
    {({ toast, handleClose }) => (
    <YStack>
    <Toast.Title>{toast.title}</Toast.Title>
    <Button onPress={handleClose}>Close</Button>
    </YStack>
    )}
    </Toast.Item>

    Toast.Title

    Styled text for the toast title. Extends SizableText.

    Toast.Description

    Styled text for the toast description. Extends SizableText.

    Toast.Close

    Close button. Extends Stack.

    Toast.Action

    Action button. Extends Stack.

    useToasts

    Hook to access toast state inside <Toast>:

    const { toasts, expanded, position } = useToasts()

    Features

    Stacking

    Multiple toasts stack visually. Hover over the stack to expand and see all toasts.

    Swipe to Dismiss

    Toasts can be swiped away. The direction is auto-detected based on position:

    • Web: Left/right positioned toasts swipe toward their edge, center toasts swipe horizontally
    • Native: All positions swipe vertically (up/down) to avoid conflicting with iOS/Android navigation back gesture

    When react-native-gesture-handler is set up via @tamagui/native/setup-gesture-handler, the toast uses native gesture coordination (activeOffsetY, failOffsetX) to prevent ScrollView from scrolling while swiping.

    Native Safe Area

    On native, toasts portal to root and automatically respect safe area insets (status bar, Dynamic Island, home indicator) when configured:

    import { SafeAreaProvider } from 'react-native-safe-area-context'
    import { useSafeAreaInsets } from 'react-native-safe-area-context'
    import { TamaguiProvider } from 'tamagui'
    function App() {
    return (
    <SafeAreaProvider>
    <AppInner />
    </SafeAreaProvider>
    )
    }
    function AppInner() {
    const insets = useSafeAreaInsets()
    return (
    <TamaguiProvider config={config} insets={insets}>
    {/* toasts will automatically avoid status bar and home indicator */}
    </TamaguiProvider>
    )
    }

    The toast reads insets from TamaguiProvider via useConfiguration().insets — the same mechanism used by other Tamagui components like Slider.

    Custom Styling

    Each part can be styled independently:

    <Toast.Item toast={t} index={i} backgroundColor="$blue5" borderRadius="$6">
    <Toast.Title color="$blue12" fontWeight="bold">
    {t.title}
    </Toast.Title>
    <Toast.Description color="$blue11">
    {t.description}
    </Toast.Description>
    </Toast.Item>

    Toaster (All-in-One)

    For simpler use cases, use the Toaster component which handles rendering internally:

    import { toast, Toaster } from '@tamagui/toast/v2'
    function App() {
    return (
    <>
    <Toaster position="bottom-right" />
    <Button onPress={() => toast('Hello!')}>Show Toast</Button>
    </>
    )
    }