React native anchored popup

react-native-anchored-popup

A slick popup element that expands towards the center of the screen from wherever the user presses down:

Screen.Recording.2022-09-19.at.1.17.17.PM.mov

Features

  • Slick opening and closing animations that expand from user press location
  • Supports 4 modes to customize positioning behavior
  • Swipe to dismiss
  • Intuitive API supporting any popup element.
  • Written in typescript

API Reference

Installation

This package depends on react-native-reanimated for animations and react-native-gesture-handler for handling gestures. If you already have those installed you can skip their installation steps and just do yarn add @good-react-native/anchored-popup.

Expo Managed Workflow:

If you’re using expo, you can just do:

npx expo install react-native-reanimated react-native-gesture-handler

And to finish installing react-native-reanimated, you’ll need to add their babel plugin to your babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['react-native-reanimated/plugin'],
  };
};
yarn add @good-react-native/anchored-popup

Bare Workflow

If you’re not using Expo’s managed workflow, there will be some additional installation steps.

First, install all packages:

yarn add @good-react-native/anchored-popup react-native-reanimated react-native-gesture-handler

Then, wrap your app in GestureHandlerRootView to finish installing gesture handler:

function App() {
  return (
    <GestureHandlerRootView style={{flex: 1}}>
      <RestOfApp />
    </GestureHandlerRootView>
  );
}

And to finish installing react-native-reanimated, you’ll need to add their babel plugin to your babel.config.js:

module.exports = {
  //...
  plugins: ['react-native-reanimated/plugin'],
};

Lastly, install pods to run on iOS: npx pod-install

Usage

Wrap your app in the AnchoredPopupProvider:

function App() {
  return (
    <AnchoredPopupProvider>
      <RestOfApp />
    </AnchoredPopupProvider>
  );
}

Create a touchable component with the component AnchoredPopupTouchableOpacity. When it is pressed, it will show the popupElement (which can be any React Native element or a render function):

<AnchoredPopupTouchableOpacity
  popupElement={
    <View>
      <Text>I Will be shown when the touchable is pressed!</Text>
    </View>
  }>
  <Text>A button that when pressed will show the popup element</Text>
</AnchoredPopupTouchableOpacity>

<AnchoredPopupTouchableOpacity/> works just like React Native’s touchable opacity =D.

Modes

The mode prop supports 4 different values to customize the positioning behavior of the popup. The mode determines the final position calculation.

'stick' Mode (default)

'stick' mode ensures that the user’s press position will be contained within the popup menu.

stick.mp4

'center-x' Mode

'center-x' mode will center the popup horizontally in the screen, while the vertical position will still stick to the users press position:

center-x.mp4

'center-y' Mode

'center-y' mode will center the popup vertically in the screen, while the horizontal position will stick to the users press position:

center-y.mp4

'center' Mode

'center' mode will center the popup in the screen horizontally and vertically:

center.mp4

Closing the popup

By default, popup will automatically close when it’s swiped away or when the backdrop is pressed (both behaviors can be disabled).

Closing programatically

There are two ways to close the popup programatically.

Either use a handle (similar to a normal ref):

function MyComponent() {
  const handle = usePopupHandle();

  function close() {
    if (handle.current) handle.current.close();
  }

  return (
    <AnchoredPopupTouchableOpacity
      //...
      handle={handle}
    />
  );
}

Or by call the close function that gets passed to the popup element (when popupElement is a render function):

function MyComponent() {
  return (
    <AnchoredPopupTouchableOpacity
      popupElement={({close}) => {
        return (
          <View>
            <TouchableOpacity onPress={close}>
              <Text>Press to Close</Text>
            </TouchableOpacity>
          </View>
        );
      }}
    />
  );
}

Each method should work equally well.

API

<AnchoredPopupTouchableOpacity/>

A touchable opacity that shows the popupElement prop when it is pressed.

Props

Accepts all TouchableOpacity props. Additionally, it accepts the following:

Prop Required? Type Description Default
popupElement Yes ReactNode | (vars: {close: ()=>void})=>ReactNode A React Native element or render function that will be shown when the popup is opened. None
animationDuration No number Time in ms that each of the animations take to complete. 150
backgroundColor No string Color of the backdrop that is shown when the popup is shown. ‘rgba(0,0,0,0.07)’
closeOnBackdropPress No boolean Whether the popup should close when the backdrop is pressed. true
handle No MutableObjectRef A handle that can be used to close the popup imperatively. undefined
mode No ‘stick’ | ‘center-x’ | ‘center-y’ | ‘center’ Determines how the popups final position is calculated. See mode ‘stick’
onAnchorChange No (anchor: AnchoredPopupAnchor | null)=>void A callback function that is called when the anchor changes in case you want to synchronize other UI changes with the anchored popups. undefined
swipeToClose No boolean Whether the popup can be swiped to dismiss. true
openOnEvent No ‘onPress’ | ‘onLongPress’ Which event causes the popup to open. ‘onPress’

GitHub

View Github