npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@backpackapp-io/react-native-toast

v0.12.1

Published

A toasting library for React Native. Built in features such as swipe to dismiss, multiple toasts, & no context power this library.

Downloads

19,836

Readme

React Native Toast

runs with expo GitHub license npm

A toast library for react-native, built on react-hot-toast. It supports features such as multiple toasts, keyboard handling, swipe to dismiss, positional toasts, and JS promises. It runs on iOS, android, and web.

video

Why?

I know what you might be thinking (jeez, another toast library?). Trust me here, this is the last toast library you will need. I built this library to meet my specific app needs and decided to open-source it after realizing that it truly is a top-notch toast library. Just give it a try.

Features

  • Multiple toasts, multiple options. Want a toast on the top, bottom, different colors, or different types at the same time? Got it.
  • Keyboard handling (both iOS and Android). Move those toasts out of the way and into view when the user opens the keyboard
  • Swipe to dismiss
  • Positional toasts (top & bottom)
  • Customizable (custom styles, dimensions, duration, and even create your own component to be used in the toast)
  • Add support for promises <-- Really! Call toast.promise(my_promise) and watch react-native-toast work its magic, automatically updating the toast with a custom message on success -- or an error message on reject.
  • Runs on web
  • Support for native modals
  • Callbacks for onPress, onShow, and onHide

Getting Started

Installation

yarn add @backpackapp-io/react-native-toast
# or
npm i @backpackapp-io/react-native-toast

Peer Dependencies

Install and link react-native-reanimated, react-native-safe-area-context, and react-native-gesture-handler

yarn add react-native-reanimated react-native-safe-area-context react-native-gesture-handler

Ensure you follow the installation of each package

Using expo?

npx expo install react-native-reanimated react-native-safe-area-context react-native-gesture-handler

Cool, now what?

Wrap your App with <GestureHandlerRootView /> and <SafeAreaProvider /> & add the <Toasts /> component to the root of your app.

Call toast("My Toast Message") whenever you are ready from anywhere in your app.

import { View, StyleSheet, Text } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { toast, Toasts } from '@backpackapp-io/react-native-toast';
import { useEffect } from 'react';

export default function App() {
  useEffect(() => {
    toast('Hello');
  }, []);

  return (
    <SafeAreaProvider>
      <GestureHandlerRootView style={styles.container}>
        <View>{/*The rest of your app*/}</View>
        <Toasts /> {/* <---- Add Here */}
      </GestureHandlerRootView>
    </SafeAreaProvider>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Example

Regular Toast

toast("This is my first toast", {
  duration: 3000,
});

Promise Toast

const sleep = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve({
        username: 'Nick',
      });
    } else {
      reject('Username is undefined');
    }
  }, 2500);
});

toast.promise(
  sleep,
  {
    loading: 'Loading...',
    success: (data: any) => 'Welcome ' + data.username,
    error: (err) => err.toString(),
  },
  {
    position: ToastPosition.BOTTOM,
  }
);

Loading Toast

const id = toast.loading('I am loading. Dismiss me whenever...');

setTimeout(() => {
  toast.dismiss(id);
}, 3000);

Success Toast

toast.success('Success!', {
  width: 300
});

Error Toast

toast.error('Wow. That Sucked!');

Documentation

<Toasts />

Include the <Toasts /> component in the root of your app.

Props

overrideDarkMode (boolean | undefined) (optional)

Override the system dark mode. If a value is supplied (I.e. true or false), then the toast components will use that value for the dark mode. For example, if overrideDarkMode = {false}, dark mode will be disabled, regardless of the system's preferences.

extraInsets (object) (optional)

Supply the container for the toasts extra padding.

extraInsets?: {
  top?: number;
  bottom?: number;
  right?: number;
  left?: number;
};

onToastShow (function) (optional)

When a toast is shown, this callback will fire, returning the toast object that was shown. Note, the toast object is "shown" when the toast is mounted.

onToastShow?: (toast: T) => void;

onToastHide (function) (optional)

When a toast is hidden, this callback will fire, returning the toast object that was hidden. Note, the toast object is "hidden" when the toast is unmounted.

onToastHide?: (toast: T) => void;

onToastPress (function) (optional)

When a toast is pressed, this callback will fire, returning the toast object that was pressed.

onToastPress?: (toast: T) => void;

defaultStyle (object) (optional)

Supply default styles for the toast component. This will be applied to all toasts unless overridden by the toast options.

defaultStyle?: {
  view?: ViewStyle;
  pressable?: ViewStyle;
  text?: TextStyle;
  indicator?: ViewStyle;
};

providerKey (string) (optional)

Provide the Toasts component with a providerKey to conditionally render toasts in a component. Useful for rendering toasts in native modals.

// Component in native modal
<Toasts providerKey="MODAL::1" />

//...
// Root component
<Toasts /> //has default providerKey of DEFAULT

//...
// Call toast in root modal

const id = toast("Hello from root modal") //default providerKey of DEFAULT

// Native modal becomes visible
const id = toast("Hello from native modal", {providerKey: "MODAL::1"})
//Now, toast is shown only in native modal

If you want to persist toasts across components (i.e. when you open/close a modal and want to keep the same toasts), your toasts should be assigned a providerKey of "PERSISTS".

toast("Message...", {providerKey: "PERSISTS"})

Or, if you cannot do so, you can update each toast manually.

const { toasts } = useToasterStore(); //Note, no provider key passed in

useEffect(() => {
  toasts.forEach((t) => {
    toast(t.message, {
      ...t,
      providerKey: isModalVisible ? 'MODAL::1' : 'DEFAULT', //Switch provider key here
    });
  });
}, [isModalVisible]);

Example

<Toasts
  onToastPress={(t) => {
    console.log(`Toast ${t.id} was pressed.`)
  }}
  overrideDarkMode={isAppDarkMode}
/>

toast() API

Call it to create a toast from anywhere, even outside React (hello errors from controllers). Make sure you add the <Toasts/>component to your app first.

Available toast options

You can provide ToastOptions as the second argument. All arguments are optional.

toast('Hello World', {
  duration: 4000,
  position: ToastPosition.TOP,
  icon: '👏',
  styles: {
    view: ViewStyle,
    pressable: ViewStyle,
    text: TextStyle,
    indicator: ViewStyle
  },
  animationType: 'timing' | 'spring',
  animationConfig: {
    flingPositionReturnDuration: number,
    ...(springConfig | timingConfig)
  },
});

Creating a toast

Blank

toast('Hello World');

The most basic variant.

Success

toast.success('Successfully created!');

Creates a notification with a success indicator on the left.

Error

toast.error('This is an error!');

Creates a notification with an error indicator on the left.

Custom (JSX)

toast("", {
  customToast: (toast) => (
    <View>
      <Text>{toast.message}</Text>
    </View>
   )
})

Creates a custom notification with JSX. Have complete control over your toast.

Full example

toast(Math.floor(Math.random() * 1000).toString(), {
  width: screenWidth,
  disableShadow: true,
  customToast: (toast) => {
    return (
      <View
        style={{
          height: toast.height,
          width: toast.width,
          backgroundColor: 'yellow',
          borderRadius: 8,
        }}
      >
        <Text>{toast.message}</Text>
      </View>
    );
  },
});

Loading

const id = toast.loading('Waiting...');

//Somewhere later in your code...

toast.dismiss(id);

This will create a loading notification. Most likely, you want to update it afterwards. For a friendly alternative, check out toast.promise(), which takes care of that automatically.

Promise

This shorthand is useful for mapping a promise to a toast. It will update automatically when the promise resolves or fails.

Simple Usage

const myPromise = fetchData();

toast.promise(myPromise, {
  loading: 'Loading',
  success: 'Got the data',
  error: 'Error when fetching',
});

Prevent Swipe to Dismiss

toast('This toast cannot be swiped away', {
  duration: 4000,
  position: ToastPosition.TOP,
  isSwipeable: false, // <-- Add here (defaults to true)
})

Advanced

You can provide a function to the success/error messages to incorporate the result/error of the promise. The third argument is toastOptions.

toast.promise(
  myPromise,
  {
    loading: 'Loading',
    success: (data) => `Successfully saved ${data.name}`,
    error: (err) => `This just happened: ${err.toString()}`,
  },
  {
    duration: 2000
  }
);

Default durations

Every type has its own duration. You can overwrite them duration with the toast options.

| type | duration | |-----------|----------| | blank | 4000 | | error | 4000 | | success | 2000 | | custom | 4000 | | loading | Infinity |

Animation Options

You can now control the animation type and configuration for toasts.

Props

  • animationType ('spring' | 'timing', optional): Choose the animation type for toast appearance. By default, toasts positioned at the bottom use spring, and those at the top use timing.
  • animationConfig (object, optional): Customize the animation configuration for spring or timing.

Example Usage

import { toast } from 'react-native-toast';

// Show a toast with custom animation settings
toast.show('This is a toast message', {
  animationType: 'spring',
  animationConfig: {
    duration: 500,
    stiffness: 100,
  },
  position: 'top',
});

Global Animation Configuration/Type

You can define a globalAnimationType and a globalAnimationConfig that sets the default animation configuration for all toasts. If an individual toast specifies its own animationConfig, it will override this global setting.

Props

  • globalAnimationConfig (object, optional): Provides a default configuration for toast animations using either spring or timing options.

Example Usage

import { Toasts } from 'react-native-toast';

// In your component
<Toasts
  globalAnimationType="spring"
  globalAnimationConfig={{
    duration: 500,
    stiffness: 120,
  }}
/>

// Or when showing a toast
toast.show('This is a toast message', {
  position: 'bottom',
  animationType: 'spring',
  animationConfig: {
    duration: 400,
    damping: 10,
  },
});

Dismiss toast programmatically

You can manually dismiss a notification with toast.dismiss. Be aware that it triggers the exit animation and does not remove the Toast instantly. Toasts will auto-remove after 1 second by default.

Dismiss a single toast

const toastId = toast('Loading...');

// ...

toast.dismiss(toastId);

You can dismiss all toasts at once, by leaving out the toastId.

Dismiss all toasts at once

toast.dismiss();

To remove toasts instantly without any animations, use toast.remove.

Remove toasts instantly

toast.remove(toastId);

// or

toast.remove();

Update an existing toast

Each toast call returns a unique id. Use in the toast options to update the existing toast.

const toastId = toast.loading('Loading...');

// ...

toast.success('This worked', {
  id: toastId,
});

Prevent duplicate toasts

To prevent duplicates of the same kind, you can provide a unique permanent id.

toast.success('Copied to clipboard!', {
  id: 'clipboard',
});

Adjust toast width to hug text

To have the toast adjust its width based on the content of the text, you can apply the following styles.

styles: {
  pressable: {
    maxWidth: width - 32,
    alignSelf: 'center',
    left: null,
    paddingHorizontal: 16
  },
  view: {
    flexGrow: 1,
    flexShrink: 1,
    maxWidth: width - 32,
    paddingHorizontal: 0,
    width: undefined
  },
  text: {
    flex: undefined,
    flexGrow: 1,
    flexShrink: 1,
    flexWrap: 'wrap'
  }
}

These styles can be applied to the defaultStyle prop in the component or to each toast instance individually. If you use these styles frequently, I recommend creating an object that you can add directly to each toast call, e.g.,

toast('my toast', {
  styles: AutoWidthStyles
});

where AutoWidthStyles holds the actual styles for auto width.

ToastOptions all optional

| Option Name | Type | Possible Values | |---------------------------------|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | string | Given an id, update the toast with the following options | | message | string | The message to render in the toast | | position | ToastPosition.TOP, ToastPosition.BOTTOM, number | The position of the toast. Use the ToastPosition enum to effectively set it | | duration | number | the duration (in ms) to show the toast for | | customToast | function | override the toast body and apply a custom toast. Receives the toast as a parameter I.e. (toast: Toast) => JSX.Element | | height | number | the minimum height of the toast Must set here even if you are using a custom toast or applying it in the styles.view/pressable to ensure calculations are accurate | | width | number | the width of the toast | | icon | JSX.Element, string | Render an icon to the left of the message | | styles | object | the styles to apply to the toast | | disableShadow | boolean | Disable the shadow underneath the toast | | isSwipeable | boolean | Control whether the toast can be dismissed with a swipe or not | | animationConfig | object | Control the fade duration, stiffness, and return duration of the toast | | accessabilityMessage | string | Optional text that will be announced when screen reader is on (Accessability Option) | | preventScreenReaderFromHiding | boolean | If the screen reader is enabled, continue to show toasts |

Styles object

{
  pressable?: ViewStyle;
  view?: ViewStyle;
  text?: TextStyle;
  indicator?: ViewStyle;
};

Thank you react-hot-toast

react-native-toast is built with modified react-hot-toast internals? Why? Well, react-native doesn't really need all the unnecessary web fluff (aria what?). So, I trimmed it down and made it perfect for mobile development by battle testing it on mobile devices and creating react-native components built specifically for iOS and Android development.

Author

Nick DeBaise on LinkedIn

Email me directly: [email protected]

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT

Made with create-react-native-library

Todos

  • Add unit tests for Components and hooks
  • Allow theming in <Toasts />
  • Queue manager