@kawaiininja/drawer
v1.0.18
Published
Adaptive Drawer component for Onyx Framework
Maintainers
Readme
@kawaiininja/drawer
An adaptive, touch-friendly drawer component for React applications. It automatically switches between a side panel (desktop) and a bottom sheet (mobile) with high-end spring animations and interactive gestures.
Features
- Adaptive Layout: Side panel on desktop, bottom sheet on mobile.
- Portal Rendering: Bulletproof rendering via React Portal to avoid z-index/overflow issues.
- Universal Dragging: Drag from anywhere on the panel to close (mobile & desktop).
- Smooth Spring Physics: Refined exponential easing for a premium, non-overshooting feel.
- Bulletproof Scroll Lock: Absolute body locking to prevent background leaking.
- Interactive Loading State: Pulse-stretching handle bar for async operations.
- Design Tokens: Fully tokenized z-indices, durations, and easings.
- Tailwind Compatible: Easy to style with Onyx-standard utility classes.
Installation
npm install @kawaiininja/drawerTailwind Configuration
Add the drawer to your content configuration to ensure internal styles (like the handle bar) are correctly applied:
// tailwind.config.js
module.exports = {
content: [
// ...
"./node_modules/@kawaiininja/drawer/dist/**/*.{js,ts,jsx,tsx}",
],
// ...
};Usage
import { AdaptiveDrawer } from "@kawaiininja/drawer";
import { useState } from "react";
function App() {
const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleSave = async () => {
setIsLoading(true);
await new Promise((r) => setTimeout(r, 2000));
setIsLoading(false);
setIsOpen(false);
};
return (
<div>
<button onClick={() => setIsOpen(true)}>Open Drawer</button>
<AdaptiveDrawer
isOpen={isOpen}
onClose={() => setIsOpen(false)}
isLoading={isLoading}
closeOnOutsideTap={true}
title={<h2>Settings</h2>}
side="right"
width="480px"
footer={<button onClick={handleSave}>Save Changes</button>}
>
<div className="space-y-4">
<p>Drawer content goes here...</p>
</div>
</AdaptiveDrawer>
</div>
);
}Props
| Prop | Type | Default | Description |
| -------------------- | ------------------- | ---------- | ----------------------------------------------- |
| isOpen | boolean | required | Controls if the drawer is visible |
| onClose | function | required | Callback when the drawer should close |
| title | ReactNode | - | Header content |
| children | ReactNode | - | Main drawer content |
| footer | ReactNode | - | Optional sticky footer content |
| side | "left" \| "right" | "right" | Which side the panel appears on desktop |
| width | string | "480px" | Width of the panel on desktop |
| isLoading | boolean | false | Animates the handle bar with a pulse-stretch |
| closeOnOutsideTap | boolean | true | Whether clicking the backdrop closes the drawer |
| className | string | "" | Additional CSS classes for the drawer panel |
| containerClassName | string | "" | Additional CSS classes for the backdrop/overlay |
Theming (CSS Variables)
You can easily customize the drawer's appearance by overriding these CSS variables in your global style file:
:root {
/* Colors */
--drawer-bg: #000000;
--drawer-border: #27272a;
--drawer-overlay: rgba(9, 9, 11, 0.8);
--drawer-handle: #27272a;
--drawer-text: #ffffff;
--drawer-text-muted: #a1a1aa;
--drawer-footer-bg: #000000;
--drawer-footer-border: #18181b;
/* Layout & Dimensions */
--drawer-width-desktop: 480px;
--drawer-max-height-mobile: 92dvh;
--drawer-radius-mobile: 2.5rem;
--drawer-radius-desktop: 2rem;
/* Z-Index */
--drawer-z-overlay: 99998;
--drawer-z-drawer: 99999;
}Design Tokens
The component uses a centralized token system for consistency:
- Spring Easing:
cubic-bezier(0.19, 1, 0.22, 1)(Smooth Exponential) - Standard Durations: Fast (200ms), Normal (400ms), Slow (500ms)
- Z-Indices: Overlay (99998), Drawer (99999)
