@luciodale/swipe-bar
v1.4.1
Published
Gesture driven React sidebar with spring physics. Touch and mouse support, native app feel for mobile first web interfaces. Tiny bundle, zero runtime dependencies.
Downloads
117
Maintainers
Readme
Documentation · NPM · GitHub
Why swipe-bar
Coming from Vaul, shadcn Sheet, react-sliding-pane, or hand-rolled Framer Motion panels, these are the behaviors you get without wiring:
- Edge swipe to open. Drag from the edge on touch. No bolting gesture libraries on top of a dialog.
- Drag to close with velocity commit. Flick to dismiss, soft release snaps back. Native iOS and Android drawer feel.
- Spring physics, no motion library. The animation engine is built in. Zero runtime dependencies.
- Mouse and touch parity. The same gesture works on desktop pointers, not only mobile.
- Multi instance per side. Two or more sidebars on the same edge with independent state.
- Bottom sheet with mid anchor. Half-open stop and full-open stop, like native sheets.
- Accessible. Focus trap, Escape to close, aria attributes, keyboard nav.
Full comparisons: vs Vaul (same category gesture drawer) · vs shadcn sheet (modal dialog vs drawer)
Install
npm install @luciodale/swipe-barQuick Start
import { SwipeBarProvider, SwipeBarLeft } from "@luciodale/swipe-bar";
function App() {
return (
<SwipeBarProvider>
<SwipeBarLeft className="bg-gray-900 text-white">
<nav>
<a href="/dashboard">Dashboard</a>
<a href="/settings">Settings</a>
</nav>
</SwipeBarLeft>
<main>Your app content</main>
</SwipeBarProvider>
);
}Swipe from the left edge on mobile or click the toggle on desktop. That's it.
Features
- Zero dependencies — just React
- Left, right, and bottom — all three directions with the same API
- Native touch gestures — edge swipe detection, drag tracking, velocity commit/cancel
- Multi-instance — multiple sidebars per direction with independent state via
idprop - Bottom sheets with mid-anchor — swipe to a halfway stop, then again to fully open
- Typed sidebar metadata — attach a generic type map and get compile-time safety
- Programmatic control — open, close, and read state from anywhere via context hook
- Cross-direction locking — one direction at a time, no gesture conflicts
- Accessibility — focus trap, Escape to close, aria attributes, keyboard navigation
- Runtime configuration — change any prop at runtime via
setGlobalOptions
Programmatic Control
import { useSwipeBarContext } from "@luciodale/swipe-bar";
function Header() {
const { openSidebar, closeSidebar, isLeftOpen } = useSwipeBarContext();
return (
<header>
<button onClick={() => openSidebar("left")}>Menu</button>
</header>
);
}Bottom Sheets
import { SwipeBarBottom } from "@luciodale/swipe-bar";
<SwipeBarBottom sidebarHeightPx={400} isAbsolute midAnchorPoint>
<div>Sheet content</div>
</SwipeBarBottom>Multi-Instance
Give each sidebar a unique id. Each instance operates independently.
<SwipeBarLeft id="nav" isAbsolute>
<nav>Navigation</nav>
</SwipeBarLeft>
<SwipeBarLeft
id="settings"
isAbsolute
swipeToOpen={false}
showToggle={false}
swipeBarZIndex={70}
overlayZIndex={65}
>
<div>Settings panel</div>
</SwipeBarLeft>const { openSidebar, leftSidebars } = useSwipeBarContext();
openSidebar("left", { id: "settings" });
const isSettingsOpen = leftSidebars.settings?.isOpen ?? false;Docs
Full documentation, configuration reference, and live examples at koolcodez.com/projects/swipe-bar.
License
MIT
