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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@elberpg/ex-modal

v2.0.1

Published

Non-native modal for React Native / Expo — no conflicts with toasts or overlays

Readme

@elberpg/ex-modal

Non-native modal and drawer for React Native / Expo.
Uses position: absolute + Animated — no native Modal component, no conflicts with toasts or other overlays.

npm version license platform

Spanish docs: README_ES.md


Preview

ExModal

| Center | Bottom sheet | |:-:|:-:| | Modal center | Modal bottom |

ExModalDrawer

| Left drawer | Top drawer | |:-:|:-:| | Drawer left | Drawer top |

Fully themeable — custom styles applied at render time.

| Square ⬛ — Center | Square ⬛ — Left drawer | Square ⬛ — Right drawer | |:-:|:-:|:-:| | Square center | Square left drawer | Square right drawer |


Installation

npm install @elberpg/ex-modal

Concept

@elberpg/ex-modal uses a position: absolute overlay instead of React Native's native Modal component.

This means it renders as a regular view layered on top of your screen — no native modal stack, no issues with toasts or notification banners that appear above native modals.

// ExModal and ExModalDrawer sit outside your scroll/content area
return (
  <>
    <SafeAreaView>
      <ScrollView>...</ScrollView>
    </SafeAreaView>

    <ExModal visible={open} onClose={() => setOpen(false)} position="center">
      <MyDialog />
    </ExModal>

    <ExModalDrawer visible={menuOpen} onClose={() => setMenuOpen(false)} position="left">
      <MyMenu />
    </ExModalDrawer>
  </>
);

Two components are available:

  • ExModal — overlay for dialogs, bottom sheets, and top banners
  • ExModalDrawer — side drawer (left, right, top, bottom)

ExModal

Animated overlay supporting center, bottom sheet, and top positions.

import { ExModal } from '@elberpg/ex-modal';

<ExModal visible={open} onClose={() => setOpen(false)} position="bottom">
  <View style={styles.sheet}>
    <Text>Your content here</Text>
  </View>
</ExModal>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | visible | boolean | — | Shows or hides the modal | | onClose | () => void | — | Called when the backdrop is tapped | | children | ReactNode | — | Modal content | | position | 'center' \| 'top' \| 'bottom' | 'center' | Modal position on screen | | animation | 'scale' \| 'slide' \| 'fade' | auto | Entry animation (scale for center, slide for top/bottom) | | backdropColor | string | global style | Overrides backdrop color for this instance | | backdropOpacity | number | 0.5 | Backdrop opacity 0–1 | | animationDuration | number | 250 | Animation duration in ms | | contentStyle | ViewStyle | — | Style for the content wrapper | | closeOnBackdrop | boolean | true | Close when backdrop is tapped | | keepMounted | boolean | false | Keep content mounted when hidden | | renderBackdrop | ({ onClose }) => ReactNode | — | Replace the default backdrop |


ExModalDrawer

Side drawer that slides in from left, right, top, or bottom.

import { ExModalDrawer } from '@elberpg/ex-modal';

<ExModalDrawer visible={open} onClose={() => setOpen(false)} position="left" size="80%">
  <View style={styles.drawer}>
    <Text>Drawer content</Text>
  </View>
</ExModalDrawer>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | visible | boolean | — | Shows or hides the drawer | | onClose | () => void | — | Called when the backdrop is tapped | | children | ReactNode | — | Drawer content | | position | 'left' \| 'right' \| 'top' \| 'bottom' | 'left' | Which side the drawer slides from | | size | number \| string | '80%' | Width (left/right) or height (top/bottom) — px or '%' | | backdropColor | string | 'rgba(0,0,0,0.4)' | Backdrop color | | backdropOpacity | number | 1 | Backdrop opacity | | animationDuration | number | 280 | Animation duration in ms | | closeOnBackdrop | boolean | true | Close when backdrop is tapped | | contentStyle | ViewStyle | — | Style applied to the drawer container |


Global styles — ExModal.styles

Override fields before the first render to apply changes app-wide.

import { ExModal } from '@elberpg/ex-modal';

ExModal.styles.backdrop         = { backgroundColor: 'rgba(0,0,0,0.65)' };
ExModal.styles.inputButton      = { borderRadius: 4, borderColor: '#007aff', backgroundColor: '#fff' };
ExModal.styles.inputLabel       = { fontSize: 12, color: '#888' };
ExModal.styles.inputText        = { fontSize: 16, color: '#000' };
ExModal.styles.inputPlaceholder = { fontSize: 16, color: '#bbb' };

Available fields

| Field | Type | Description | |-------|------|-------------| | backdrop | { backgroundColor: string } | Semi-transparent overlay behind the modal | | inputButton | ViewStyle | Container for an input-style trigger button | | inputLabel | TextStyle | Label above the input button | | inputText | TextStyle | Text showing the selected value | | inputPlaceholder | TextStyle | Placeholder text when no value is set |


Render props

Replace any visual element with your own component.

<ExModal
  renderBackdrop={({ onClose }) => (
    <Pressable style={StyleSheet.absoluteFill} onPress={onClose}>
      <BlurView intensity={60} style={StyleSheet.absoluteFill} />
    </Pressable>
  )}
>
  <MyContent />
</ExModal>

Important rule

Modals use position: absolute — place them outside any ScrollView.

// ✅ Correct
return (
  <>
    <SafeAreaView>
      <ScrollView>...</ScrollView>
    </SafeAreaView>
    <ExModal visible={open} onClose={onClose}>
      <MyContent />
    </ExModal>
  </>
);

// ❌ Wrong — the modal will scroll with the content
return (
  <ScrollView>
    <ExModal visible={open} .../>
  </ScrollView>
);