React native customizable toast library based on reanimated 2 layout animations
react-native-customizable-toast
yet another toast library based on reanimated 2 layout animations
Features
- Imperative API
- Fully Customizable
- Custom toast renderer
- Custom vertical swipe animations
- Custom layout animations
 
- Swipeable both vertical and horizontal
- Fully typed with TypeScript
Requirements
- react-native-reanimated ^2.3.0
- react-native-gesture-handler ^1.10.0
Installation
npm install react-native-customizable-toast
Basic Usage
Use default Toaster component in your base component.
import { Toaster } from "react-native-customizable-toast";
export default function App() {
  return (
    <View style={{ flex: 1 }}>
      <Content />
      <Toaster />
    </View>
  );
}
Use ToasterHelper to show a simple toast.
import { ToasterHelper } from "react-native-customizable-toast";
ToasterHelper.show({
  text: 'lorem ipsum',
  type: 'success',
  timeout: 5000,
});
Default Methods
// show toast
const toast = ToasterHelper.show({
  text: 'custom string',
  timeout: 5000,
  type: 'info',
  onPress: () => {},
  dismissible: false,
  loading: true,
});
// update toast
ToasterHelper.update(toast, {
  dismissible: true,
  loading: false,
});
// hide toast
ToasterHelper.hide(toast)
Customizing
In case that you don’t want to use default Fade animations and want to replace them with Slide animations and specify custom properties for toast message;
First create responsible type for your custom toast.
type MyCustomToaster = {
  text: string;
  dismissible?: boolean;
  backgroundColor?: string;
};
Create ref object to use toaster methods via imperative api. You can create helper object to get rid of ‘current’ keyword.
const CustomToasterRef = createRef<ToasterMethods<MyCustomToaster>>();
// optional
export const CustomToasterHelper = {
  show: (options: MyCustomToaster) => CustomToasterRef.current?.show(options)!,
  hide: (id: string) => CustomToasterRef.current?.hide(id),
  filter: (fn: (value: MyCustomToaster, index: number) => void) =>
    CustomToasterRef.current?.filter(fn),
  update: (id: string, options: Partial<MyCustomToaster>) =>
    CustomToasterRef.current?.update(id, options),
};
Next, create a toaster component based on ToasterBase, attach the ref object to it and customize a bit. You can use Reanimated 2 Layout Animations.
https://docs.swmansion.com/react-native-reanimated/docs/next/api/LayoutAnimations/exitAnimations
import {
  SlideInLeft,
  SlideOutRight,
} from 'react-native-reanimated';
export const CustomToaster = () => {
  return (
    <ToasterBase
      entering={SlideInLeft}
      exiting={SlideOutRight}
      ref={CustomToasterRef}
    />
  );
};
By default onSwipeEdge callback removes all toast messages from toaster but we want to remove dismissible toasts.
export const CustomToaster = () => {
  return (
    <ToasterBase
      entering={SlideInLeft}
      exiting={SlideOutRight}
      ref={CustomToasterRef}
      onSwipeEdge={({ filter }) => filter((e) => !e.dismissible)} // <--- add
    />
  );
};
Since we want to use a custom toast that has custom properties, we need to create a Toast component. We will use useToast hook to get the toast data from current context.
const CustomToastComponent = () => {
  const {
    text,
    hide,
    dismissible,
    backgroundColor = '#222',
  } = useToast<MyCustomToaster>();
  return (
    <Swipeable onSwipe={hide} disabled={!dismissible}>
      <View style={styles.container}>
        <TouchableOpacity
          disabled={!dismissible}
          style={[
            styles.touchable,
            {
              backgroundColor,
            },
          ]}
          onPress={hide}
        >
          <Text style={styles.text}>{text}</Text>
        </TouchableOpacity>
      </View>
    </Swipeable>
  );
};
const styles = StyleSheet.create({
  container: {
    paddingHorizontal: 10,
    paddingVertical: 2,
  },
  touchable: {
    alignItems: 'center',
    flexDirection: 'row',
    borderRadius: 5,
    padding: 10,
    minHeight: 40,
  },
  text: {
    color: '#ffffff',
    flex: 1,
  },
});
Update CustomToaster component to render out custom toast.
export const CustomToaster = () => {
  return (
    <ToasterBase
      entering={SlideInLeft}
      exiting={SlideOutRight}
      ref={CustomToasterRef}
      onSwipeEdge={({ filter }) => filter((e) => !e.dismissible)}
      render={CustomToastComponent} // <--- add
    />
  );
};
Create toast via your helper.
CustomToasterHelper.show({
  text: 'message',
  dismissible: false,
  backgroundColor: 'RANDOM HEX COLOR'
});
?Congratulations!!
You have your custom implementation of react-native-customizable-toast.
Dont mind FPS ?
What if you wanted to change the vertical stack animation to another animation?
Create Reanimated 2 worklet that returns style object. Dont forget to take a look at ToastItemProps. You can find lots of animated values and toast properties that you can combine with the provided link.
export const clamp = (
  value: number,
  lowerBound: number,
  upperBound: number
) => {
  'worklet';
  return Math.min(Math.max(lowerBound, value), upperBound);
};
export const customStyleWorklet = ({
  itemLayout: { y },
  gesture: { translationY },
  properties: { index },
}: ToastItemProps) => {
  'worklet';
  return {
    transform: [
      {
        translateY: clamp(translationY.value, -y.value, 0),
      },
      {
        translateX: interpolate(
          -translationY.value - y.value,
          [0, 100],
          [0, index % 2 ? 1000 : -1000],
          Extrapolate.CLAMP
        ),
      },
    ],
  };
};
Use custom style worklet in your toaster component.
export const CustomToaster = () => {
  return (
    <ToasterBase
      entering={SlideInLeft}
      exiting={SlideOutRight}
      ref={CustomToasterRef}
      onSwipeEdge={({ filter }) => filter((e) => !e.dismissible)}
      render={CustomToastComponent}
      itemStyle={customStyleWorklet}  // <--- add
    />
  );
};
Dont mind FPS again ?
You can find full implementation in CustomToaster
TODO
- Better README.md or docs
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT