Description:
expo-gooey-toast is a React Native toast library that creates morphing pill-to-card notifications with gooey SVG transitions.
It’s built for Expo and React Native apps, uses Reanimated 4 and react-native-svg, and supports iOS and Android.
Features
- Pill to card to pill toast transitions.
- Animate toast UI with Reanimated 4 and SVG.
- Show success, error, warning, info, and default states.
- Track async work with loading, success, and error toast flows.
- Support four body alignment patterns.
- Add action buttons for quick follow-up work.
- Show timestamps and small meta labels.
- Dismiss toasts with swipe gestures.
- Control toast lifetime with per-toast duration values.
- Export TypeScript types for app-level integration.
Use Cases
- Show save and sync feedback in an Expo form screen.
- Report API request progress during async data fetches.
- Surface validation and network errors in mobile checkout flows.
- Display lightweight status messages in admin and dashboard apps.
See It In Action
How to Use It
1. Install & setup.
# Clone the repository that contains the toast source and demo app
git clone https://github.com/rit3zh/expo-gooey-toast
# Enter the project folder
cd expo-gooey-toast
# Install dependencies with your preferred package manager
bun install
# Start the Expo development server
bun start2. The library exports GooeyToaster and gooeyToast from src/index.ts. Put the host near the top of your app tree so any screen can trigger a toast.
import React from "react";
import { View, Text, Pressable } from "react-native";
// Import the toast host and toast API from the project source
import { GooeyToaster, gooeyToast } from "@/src";
export default function App() {
return (
<View style={{ flex: 1 }}>
{/* Your app UI lives here */}
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Pressable
// Trigger a basic toast from anywhere in the tree
onPress={() => gooeyToast("Profile updated")}
>
<Text>Show toast</Text>
</Pressable>
</View>
{/* Mount one toaster instance near the root */}
<GooeyToaster position="top-center" visibleToasts={3} />
</View>
);
}3. The public API includes the base gooeyToast() call plus typed helpers for success, error, warning, and info states.
import { gooeyToast } from "@/src";
// Show a neutral message
gooeyToast("Draft stored locally");
// Show a success message
gooeyToast.success("Upload complete");
// Show an info message
gooeyToast.info("New comment received");
// Show a warning message
gooeyToast.warning("Storage is almost full");
// Show an error message with extra body text
gooeyToast.error("Request failed", {
// Add a secondary line for useful context
description: "The server did not return a valid response.",
// Move text and icon layout to the right side
bodyLayout: "right",
});4. gooeyToast.promise() is the most useful part of the API for real apps. It maps loading, success, and error states to a single promise flow. The README shows support for per-state descriptions too.
import { gooeyToast } from "@/src";
async function refreshAccount() {
const request = fetch("https://example.com/api/account").then((res) => {
if (!res.ok) {
throw new Error("Bad response");
}
return res.json();
});
gooeyToast.promise(request, {
// Text shown while the promise is still pending
loading: "Refreshing account",
// Text shown after the promise resolves
success: "Account is current",
// Text shown after the promise rejects
error: "Refresh failed",
// Per-state body text
description: {
loading: "Pulling the latest account details.",
success: "The latest records are now on this device.",
error: "Check your connection and try the request again.",
},
});
return request;
}5. Add action buttons and metadata:
import { gooeyToast } from "@/src";
gooeyToast.success("Invoice sent", {
// Add a second line under the title
description: "The customer copy is now in the outbox.",
// Show a small metadata label
meta: "billing",
// Render a timestamp on the toast
showTimestamp: true,
// Attach a direct action button
action: {
label: "Undo",
onClick: () => {
// Roll back the last action
console.log("Undo invoice send");
},
},
});6. Dismiss one toast or clear them all:
import { gooeyToast } from "@/src";
// Keep the returned ID if your implementation exposes it
const toastId = gooeyToast("Connecting to workspace");
// Later, dismiss a single toast by ID
gooeyToast.dismiss(toastId);
// Clear every visible toast
gooeyToast.dismissAll();7. All possible component props.
description(string): Adds a secondary text line under the title. ([GitHub][1])bodyLayout(“left” | “center” | “right” | “spread”): Sets the body alignment pattern. Default:"left". ([GitHub][1])duration(number): Sets the auto-dismiss time in milliseconds. Default:4000. ([GitHub][1])icon(ReactNode): Replaces the default icon area with custom content. ([GitHub][1])action({ label, onClick }): Adds one action button with a label and click handler. ([GitHub][1])meta(string): Renders compact supporting text such as a source or status label. ([GitHub][1])position(“top” | “bottom”): Sets the toast vertical direction for that toast. Default:"top". ([GitHub][1])dismissible(boolean): Turns swipe or manual dismissal on or off. Default:true. ([GitHub][1])showTimestamp(boolean): Shows a timestamp on the toast UI. Default:false. ([GitHub][1])