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

@get-set/gs-drawer

v1.0.2

Published

Get-Set Drawer

Downloads

170

Readme

@get-set/gs-drawer

A beautiful, fully-featured off-canvas drawer / sidebar with four usage modes from one codebase:

  1. window.GSDrawer(selectorOrElement, params) — native factory
  2. $(selector).GSDrawer(params) — jQuery plugin
  3. element.GSDrawer(params)HTMLElement.prototype method
  4. <GSDrawer> — React component with a typed imperative ref

All four share the same actions/, constants/, helpers/ and types/, so behaviour is identical everywhere. It slides in from any edge with polished, side-aware animations, a rich backdrop layer catalog (shared with GSModal), push-content mode, swipe-to-close, full keyboard + ARIA accessibility, light / dark / auto theming, RTL, and sensible defaults.

Features

  • Four anchor sidesleft · right · top · bottom.
  • Sizessm · md · lg · xl · full, or an explicit width / height.
  • Backdrop layer catalogdim · blur · glass · gradient · vignette · tint · none, on top of the backdrop / backdropColor / backdropOpacity / backdropBlur primitives.
  • Beautiful animations — side-aware slide / slide-over / reveal / flip / swing, plus fade / scale; independent enter/exit, per-instance duration & easing, prefers-reduced-motion aware.
  • Push content — translate the page aside instead of overlaying it.
  • Swipe to close — drag the panel toward its edge; release past a threshold to dismiss.
  • Header / footer — optional title, subtitle, footer HTML; sticky while the body scrolls.
  • Dismissal controlcloseOnBackdrop, closeOnEsc, persistent, 'static' backdrop (shakes).
  • Focus management — focus trap, auto-focus, initialFocus, return-focus on close.
  • Scroll lock — body scroll lock with scrollbar-gap compensation.
  • Theminglight / dark / auto (+ accent color), RTL.
  • Stacking — nested drawers layer with incrementing z-index; Esc closes the topmost.
  • React-only gsx — scoped per-instance styles injected/removed automatically.
  • Instance registrywindow.GSDrawerConfigue.instance(key).

Compatibility

  • Modern browsers (ES2020).
  • React 16.8+ / 17 / 18 / 19 (peer dependency, optional — the native/jQuery/prototype modes need no React).
  • Ships a bundled dist-js/bundle.js for <script> / jQuery / prototype use, and an ESM dist/ build for React/bundlers.

Project layout

GSDrawer.ts                     window.GSDrawer factory (native entry)
actions/                        init · open · close · destroy · refresh · animate · focusTrap · getCurrentParams
constants/                      animations · sizes · defaultParams
helpers/                        layout · swipe · uihelpers
types/                          params · ref · global.d.ts
components/GSDrawer.tsx         React component (forwardRef + GSDrawerHandle)
components/styles/              GSDrawer.css · .scss · GSDrawerCSS.ts (injected by React)
styles/                         GSDrawer.css · .scss (for native/<link>)
example.html                    native showcase
tests/                          vitest suites (logic · native · react)

Install

npm i @get-set/gs-drawer

Build & test

npm run build     # webpack bundle (dist-js) + tsc React build (dist)
npm test          # vitest

The build emits no .map files and contains no sourceMappingURL.


Usage — Native JS

The factory accepts a CSS selector string OR a DOM element as its first argument, then a params object. It wraps the element in an off-canvas panel and returns a Ref with imperative methods.

<link rel="stylesheet" href="node_modules/@get-set/gs-drawer/styles/GSDrawer.css" />
<script src="node_modules/@get-set/gs-drawer/dist-js/bundle.js"></script>

<button id="open">Menu</button>
<div id="menu" hidden>
  <nav>… your drawer content …</nav>
</div>

<script>
  // By selector string:
  const drawer = window.GSDrawer('#menu', {
    reference: 'main-nav',
    side: 'left',
    size: 'md',
    title: 'Navigation',
    trigger: '#open',
    backdropType: 'blur',
    animation: 'slide'
  });

  // …or by element (identical):
  // const drawer = window.GSDrawer(document.getElementById('menu'), { ... });

  drawer.openDrawer();
  drawer.toggle();
  drawer.isOpen();      // -> boolean
  drawer.closeDrawer();
</script>

jQuery

$('#menu').GSDrawer({ side: 'right', title: 'Cart', trigger: '#open-cart' });

HTMLElement prototype

document.getElementById('menu').GSDrawer({ side: 'left', swipeToClose: true });

Both adapters pass the element (not a selector) into the factory — which is why the factory must accept an element.

Instance methods (registry)

Every instance is registered in window.GSDrawerConfigue. Retrieve one by its reference and drive it imperatively:

const ref = window.GSDrawerConfigue.instance('main-nav');
ref.openDrawer();
ref.closeDrawer();
ref.toggle();
ref.isOpen();
ref.setContent('<p>Replaced body</p>');
ref.refresh();   // rebuild from (possibly mutated) params
ref.destroy();   // teardown + restore content + unregister

Usage — React

import { useRef } from 'react';
import GSDrawer, { GSDrawerHandle } from '@get-set/gs-drawer';

function App() {
  const drawer = useRef<GSDrawerHandle>(null);

  return (
    <>
      <button onClick={() => drawer.current?.open()}>Open menu</button>

      <GSDrawer
        ref={drawer}
        reference="main-nav"
        side="left"
        size="md"
        title="Navigation"
        subtitle="Where to?"
        backdropType="blur"
        animation="slide"
        swipeToClose
        onOpen={() => console.log('opened')}
        onClose={() => console.log('closed')}>
        <nav>
          <a href="#">Dashboard</a>
          <a href="#">Projects</a>
          <a href="#">Settings</a>
        </nav>
      </GSDrawer>
    </>
  );
}

Controlled mode + external trigger:

const [open, setOpen] = useState(false);

<button ref={btnRef}>Open</button>
<GSDrawer
  open={open}
  onClose={() => setOpen(false)}
  trigger={btnRef}
  side="right">
  …
</GSDrawer>

Next.js (App Router)

The component renders through a portal and guards SSR (canPortal), so it works in the App Router. Mark the file that renders it as a client component:

'use client';
import GSDrawer from '@get-set/gs-drawer';

gsx — scoped styles (React only)

gsx injects a per-instance <style data-key="…"> scoped to this drawer's overlay via [data-key], removed automatically on unmount.

<GSDrawer
  reference="fancy"
  gsx={{
    '.gs-drawer-panel': { borderRadius: '0 20px 20px 0' },
    '.gs-drawer-title': { letterSpacing: '0.02em' }
  }}>
  …
</GSDrawer>

Options / props

Native params and React props share the same names (React adds open, defaultOpen, onOpen, onClose, gsx, and children).

Identity

| Option | Type | Default | Description | | --- | --- | --- | --- | | reference | string | auto GUID | Registry key. Reused as the data-key on the overlay. | | gsx | NestedCSS | — | React only. Scoped inline styles injected for this instance. |

Placement & sizing

| Option | Type | Default | Description | | --- | --- | --- | --- | | side | 'left' \| 'right' \| 'top' \| 'bottom' | 'left' | Edge the drawer is anchored to and slides from. | | size | 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full' | 'md' | Width for left/right; height for top/bottom. | | width | number \| string | — | Explicit width (overrides size for left/right). Number = px. | | height | number \| string | — | Explicit height (overrides size for top/bottom). Number = px. |

Behaviour

| Option | Type | Default | Description | | --- | --- | --- | --- | | closeOnBackdrop | boolean | true | Close when the backdrop is clicked. | | closeOnEsc | boolean | true | Close on Escape (topmost drawer only). | | persistent | boolean | false | Non-dismissable: backdrop/Esc/× no longer close (only programmatic close). | | pushContent | boolean | false | Translate the page aside instead of overlaying it. | | pushSelector | selector \| HTMLElement \| ref | body children | Element(s) to translate when pushContent is on. | | swipeToClose | boolean | false | Enable edge-drag / swipe-to-close on the panel. | | swipeThreshold | number | 0.4 | Fraction (0–1) of the panel size past which a release closes. |

Backdrop

| Option | Type | Default | Description | | --- | --- | --- | --- | | backdrop | boolean \| 'static' | true | true = dim + click-to-close; false = no overlay; 'static' = present but shakes instead of closing. | | backdropType | catalog (below) | 'dim' | Rich backdrop layer preset. | | backdropColor | string | rgba(17,24,39,.5) | Overlay scrim color. | | backdropOpacity | number | 1 | Overlay alpha (0–1). | | backdropBlur | boolean \| number \| string | false | true=8px; number=px; string=raw CSS length. |

Animation

| Option | Type | Default | Description | | --- | --- | --- | --- | | animation | catalog (below) \| false | 'slide' | Entrance animation. false disables panel motion. | | exitAnimation | catalog \| false | mirrors animation | Separate exit animation. | | animationDuration | number \| { enter?, exit? } | 320 | Duration in ms; object sets each phase. | | animationEasing | string | cubic-bezier(.32,.72,0,1) | CSS easing for the panel. | | backdropAnimation | catalog \| false | 'fade' | Backdrop's own animation. | | backdropAnimationDuration | number | 240 | Backdrop fade duration in ms. | | reducedMotion | 'auto' \| boolean | 'auto' | Honor prefers-reduced-motion. 'auto' follows the OS. |

Presentation & close affordances

| Option | Type | Default | Description | | --- | --- | --- | --- | | title | string | — | Header title (wires aria-labelledby). | | subtitle | string | — | Secondary line under the title. | | footer | string \| false | false | Footer HTML. | | showClose | boolean | true | Show the built-in × close button. | | closeButtonPosition | 'top-end' \| 'top-start' \| 'header' \| 'outside' | 'top-end' | × button placement (RTL-aware). |

Layout / scrolling

| Option | Type | Default | Description | | --- | --- | --- | --- | | scrollable | boolean | true | Body scrolls independently; header/footer sticky. | | stickyHeader | boolean | true | Pin the header while the body scrolls. | | stickyFooter | boolean | true | Pin the footer while the body scrolls. | | lockScroll | boolean | true | Lock <body> scroll while open. | | scrollbarPadding | boolean | true | Compensate scrollbar width to avoid layout shift. |

Focus management

| Option | Type | Default | Description | | --- | --- | --- | --- | | autofocus | boolean | true | Auto-focus the first focusable / [autofocus] on open. | | initialFocus | selector \| HTMLElement \| ref \| false | — | Explicit element to focus. false focuses the panel. | | disableFocus | boolean | false | Skip auto-focus entirely. | | returnFocus | boolean | true | Restore focus to the previously focused element on close. |

Theming

| Option | Type | Default | Description | | --- | --- | --- | --- | | theme | 'light' \| 'dark' \| 'auto' | 'auto' | Visual theme. auto follows prefers-color-scheme. | | accentColor | string | #2563eb | Accent for focus ring / handle / close button (--gsd-accent). | | rtl | boolean | false | Right-to-left layout. | | customClass | GSDrawerCustomClass | — | Per-part class overrides (see below). | | className | string | — | Extra class on the overlay root. |

Wiring

| Option | Type | Default | Description | | --- | --- | --- | --- | | trigger | selector \| HTMLElement \| ref | — | Element(s) that open the drawer on click. | | closeHandler | selector \| HTMLElement \| ref | — | Element(s) inside the content that close on click. |

Callbacks

| Option | Type | Description | | --- | --- | --- | | beforeOpen | () => void \| boolean | Return false to cancel opening. | | afterOpen | () => void | Fired after the open transition. | | beforeClose | () => void \| boolean | Return false to cancel closing. | | afterClose | () => void | Fired after the drawer has fully closed. | | onOpen / onClose | () => void | React only convenience callbacks. |

customClass parts

container · backdrop · panel · header · title · subtitle · closeButton · body · footer · handle.


Variant catalogs

Side catalog

| side | Anchors to | Slides from | | --- | --- | --- | | left | left edge, full height | the left | | right | right edge, full height | the right | | top | top edge, full width | the top | | bottom | bottom edge, full width | the bottom |

Size catalog

| size | Slide-axis dimension | | --- | --- | | sm | 280px | | md | 360px (default) | | lg | 480px | | xl | 640px | | full | 100% |

width / height override the size on the relevant axis.

Backdrop type catalog

| backdropType | Look | | --- | --- | | dim | Plain dimmed scrim (honors backdropBlur). Default. | | blur | Translucent scrim + 8px backdrop blur. | | glass | Frosted light glass (blur + saturation). | | gradient | Diagonal indigo→pink gradient scrim. | | vignette | Darkened radial edges. | | tint | Subtle accent-tinted scrim (uses accentColor). | | none | No painted backdrop layer. |

Animation catalog

Side-aware animations bake the side into their keyframes automatically.

| animation | Side-aware | Description | | --- | --- | --- | | slide | ✓ | Clean edge slide. Default. | | slide-over | ✓ | Slide with a slight fade. | | reveal | ✓ | Slide + scale-from-edge with fade. | | flip | ✓ | 3D hinge on the anchored edge. | | swing | ✓ | Hinged swing with a little overshoot. | | fade | — | Cross-fade in place. | | scale | — | Scale + fade in place. | | none | — | No motion (reduced-motion fallback). | | false | — | Disable panel motion entirely. |

Theme catalog

| theme | Palette | | --- | --- | | light | Forced light. | | dark | Forced dark. | | auto | Follows prefers-color-scheme (default). |


Imperative API

React GSDrawerHandle (via ref)

| Method | Description | | --- | --- | | open() | Open the drawer. | | close() | Close the drawer. | | toggle() | Toggle open/closed. | | isOpen() | boolean — current open state. | | setContent(node) | Replace the body content with a React node. | | destroy() | Close and unregister the instance. |

Native instance (Ref)

| Method | Description | | --- | --- | | openDrawer() | Open the drawer. | | closeDrawer() | Close the drawer. | | toggle() | Toggle open/closed. | | isOpen() | boolean — current open state. | | setContent(html \| element) | Replace the body content. | | refresh() | Rebuild the overlay from current params (reopens if it was open). | | destroy() | Teardown: close, remove listeners, restore content, unregister. |

Registry — window.GSDrawerConfigue

| Member | Description | | --- | --- | | references | Array<{ key, ref }> of every live instance. | | instance(key) | Look up a Ref by its reference. |


Examples

Native — right-side cart, glass backdrop, swipe to close

const cart = window.GSDrawer('#cart', {
  reference: 'cart',
  side: 'right',
  size: 'lg',
  title: 'Your cart',
  backdropType: 'glass',
  swipeToClose: true,
  trigger: '#open-cart',
  footer: '<button id="checkout">Checkout</button>',
  closeHandler: '#keep-shopping'
});

Native — push-content sidebar

window.GSDrawer('#sidebar', {
  side: 'left',
  size: 'sm',
  pushContent: true,
  backdrop: false,
  animation: 'slide',
  trigger: '#hamburger'
});

React — bottom sheet, dark, controlled

const [open, setOpen] = useState(false);

<GSDrawer
  open={open}
  onClose={() => setOpen(false)}
  side="bottom"
  size="sm"
  theme="dark"
  backdropType="vignette"
  animation="slide"
  title="Filters">
  <FilterForm />
</GSDrawer>

License

ISC