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 🙏

© 2025 – Pkg Stats / Ryan Hefner

drawer-stack

v0.1.2

Published

Drawer stack for React

Downloads

47

Readme

iOS Card-Style Drawer Stack

A React component for creating iOS-style stacked drawer navigation using React Router.

Works in tandem with normal navigation - use full-page navigation for primary flows, or peek at routes with stackable drawers for quick previews.

Demo: https://x.com/Dan_The_Goodman/status/1938357207424503843

[!WARNING] Does not currently support <Outlet /> within a drawer

Features

  • 🔗 Works with existing React Router - No special changes needed to your routes or components, just a root layout
  • 🚀 Dual navigation modes - Same routes work as full pages OR drawer previews
  • 📚 Stackable drawers - Open multiple drawer layers that peek behind each other
  • 🎨 iOS-style stacking - Cards peek from behind with configurable spacing and scaling
  • 🔗 URL-based state - Drawer stack persists in query parameters
  • Smooth animations - Natural enter/exit animations with simultaneous transitions
  • 📱 Multiple dismiss methods - Close button, background click, or drag-to-dismiss

Basic Usage

npm i drawer-stack

1. Define your route configuration

Create a standard React Router route configuration:

// routeConfig.ts
import { type RouteObject } from "react-router"
import RootLayout from "./layouts/root"
import RootPage from "./routes/root"
import ProfilePage from "./routes/profile"
import SettingsPage from "./routes/settings"

export const routeConfig: RouteObject[] = [
  {
    path: "/",
    element: <RootLayout />,
    children: [
      {
        path: "",
        element: <RootPage />,
      },
      {
        path: "profile",
        element: <ProfilePage />,
      },
      {
        path: "settings",
        element: <SettingsPage />,
      },
    ],
  },
]

2. Add DrawerStack to your root layout

The root layout is your top-level route component (typically at path "/"). Add the DrawerStack component here so it can render drawers over your entire app:

// routes/root.tsx
import { Outlet } from "react-router"
import { DrawerStack } from 'drawer-stack'
import { routeConfig } from '../routeConfig'

export default function RootLayout() {
  return (
    <>
      {/* Where normal paths will render */}
      <Outlet />

      {/* DrawerStack renders drawers over everything */}
      <DrawerStack routes={routeConfig} />
    </>
  )
}

3. Use the hook in your components

import { useDrawerStack } from 'drawer-stack'
import { Link } from 'react-router'

function MyComponent() {
  const { pushDrawer } = useDrawerStack()

  return (
    <div>
      <button onClick={() => pushDrawer('/profile')}>
        Open Profile (Drawer)
      </button>
      <Link to="/profile">
        Go to Profile (Full Page)
      </Link>
    </div>
  )
}

Configuration

<DrawerStack
  routes={routeConfig}
  STACK_GAP={40}        // pixels between cards (default: 40)
  STACK_SQUEEZE={0.04}  // scale reduction per level (default: 0.04)
/>

API

useDrawerStack()

  • pushDrawer(path) - Add drawer to stack
  • popDrawer() - Remove top drawer
  • closeAllDrawers() - Clear entire stack
  • drawerStack - Current drawer state
  • hasDrawers - Boolean if any drawers open

For full-page navigation, just use normal React Router <Link> components or the useNavigate() hook.

URL Structure

  • ?drawer=/profile - Single drawer
  • ?drawer=/profile&drawer=/settings - Stacked drawers

How It Works

Route Integration

The DrawerStack component automatically renders your existing React Router routes inside drawers. Any route in your routeConfig can be opened as a drawer without modification.

Important: The root route ("/") cannot be displayed in a drawer to prevent infinite recursion.

Component Reusability

Your route components work identically whether rendered:

  • As a full page (normal navigation)
  • Inside a drawer (drawer navigation)

No special drawer-aware code needed in your route components!

Navigation Patterns

// Drawer navigation (stacks on top of current page)
pushDrawer('/profile')

// Stack multiple drawers
pushDrawer('/profile')
pushDrawer('/settings') // Opens on top of profile drawer

// Full page navigation (use normal React Router)
<Link to="/profile">Go to Profile</Link>
// or
const navigate = useNavigate()
navigate('/profile')

Tips

  • Performance: Only open drawers are rendered, so having many routes doesn't impact performance
  • Accessibility: Drawers include proper focus management and keyboard navigation
  • Mobile-first: Designed for touch interactions but works great on desktop too
  • URL sharing: Drawer state is preserved in the URL, so users can bookmark or share stacked states
  • Fill available space: You can simply use h-full to fill available space with your top-level element