Native Toast
Features

Architecture

State management pattern, reducer design, and technical decisions.

State Management

NativeToast uses a module-level state store with an observer pattern — not React Context. This is the key architectural decision that enables the imperative API.

Why not Context?

The toast() function must be callable from anywhere: event handlers, async callbacks, navigation handlers, non-React modules. React Context only works inside the component tree, so a module-level store is used instead.

Store Design

FeatureDetail
PatternModule-level state store with observer (not React context)
ReducerPure function handling 7 action types
ActionsADD_TOAST, UPDATE_TOAST, UPSERT_TOAST, DISMISS_TOAST, REMOVE_TOAST, START_PAUSE, END_PAUSE
TOAST_LIMITMax 3 simultaneous toasts (older dropped)
Listener systemaddListener(fn) → unsubscribe function
React bridgeuseToasterStore() hook subscribes to store via useSyncExternalStore

Upsert Behavior

When a toast is created with the same id as an existing one, the store performs an upsert (update instead of duplicate):

const id = 'my-toast';

toast.loading('Loading…', { id });
// Later, update the same toast:
toast.success('Done!', { id });

Timer & Lifecycle

FeatureDetail
Auto-dismissEach toast auto-dismisses after its duration
REMOVE_DELAY1000ms gap between dismiss (exit animation) and removal
AppState pauseTimers pause when app goes to background
AppState resumeTimers resume with correct remaining time on foreground
Pause accumulationTotal paused time tracked across multiple background cycles
Infinity durationLoading toasts excluded from timer entirely
Two-phase removalDISMISS_TOASTREMOVE_TOAST (exit anim → cleanup)
Timer cleanupAll pending timeouts cleaned up on state change

Technical Decisions

DecisionRationale
Animated (not Reanimated)Built-in, no worklet setup needed
react-native-svgAnimated SVG icons with stroke-dashoffset
PanResponder (not gesture-handler)Built-in, no extra dependency
Module-level storeAccessible outside React (imperative toast() calls)
Container-level themeSimpler API than per-toast themes
useNativeDriver: false for SVGstrokeDashoffset is not a native transform
useNativeDriver: true for entry/exitOpacity/translateY animations use native driver

Layout & Positioning

FeatureDetail
PositionTop-center (hardcoded)
topOffsetConfigurable vertical offset (default 50px)
Safe areaIntegrated via useSafeAreaInsets()
gutterConfigurable gap between expanded toasts (default 8px)
Height measurementEach toast self-measures via onLayout
Fallback height48px used before measurement completes
OverlayFull-screen absoluteFill with pointerEvents="box-none"
Max width85% of screen
Min width120px
Content layoutHorizontal row: icon (left) + message (right)
Text max lines2 lines with ellipsis
Font scalingDisabled (allowFontScaling={false})
Text selectionDisabled (selectable={false})

On this page