Side Drawer — Free HTML CSS JS Slide Panel Snippet
Side Drawer · Navigation · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="page">
<button class="open-btn" onclick="openDrawer()">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
Open Drawer
</button>
</div>
<div class="overlay" id="overlay" onclick="closeDrawer()"></div>
<aside class="drawer" id="drawer">
<div class="drawer-header">
<div class="brand">⬡ Acme</div>
<button class="close-btn" onclick="closeDrawer()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<nav class="drawer-nav">
<a href="#" class="nav-item active"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>Dashboard</a>
<a href="#" class="nav-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Users<span class="badge">12</span></a>
<a href="#" class="nav-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>Billing</a>
<a href="#" class="nav-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>Analytics</a>
<div class="nav-section">Settings</div>
<a href="#" class="nav-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M4.93 4.93a10 10 0 0 0 0 14.14"/></svg>Preferences</a>
<a href="#" class="nav-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>Sign out</a>
</nav>
<div class="drawer-footer">
<div class="user-pill">
<div class="user-av">PS</div>
<div><div class="user-name">Puneet Sharma</div><div class="user-role">Admin</div></div>
</div>
</div>
</aside>* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.open-btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; background: #6366f1; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; font-family: inherit; }
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); backdrop-filter: blur(2px); opacity: 0; pointer-events: none; transition: opacity 0.25s; z-index: 10; }
.overlay.show { opacity: 1; pointer-events: all; }
.drawer {
position: fixed; top: 0; left: 0; bottom: 0; width: 260px;
background: #fff; box-shadow: 4px 0 24px rgba(0,0,0,0.1);
display: flex; flex-direction: column;
transform: translateX(-100%);
transition: transform 0.3s cubic-bezier(0.4,0,0.2,1);
z-index: 20;
}
.drawer.open { transform: translateX(0); }
.drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 16px; border-bottom: 1px solid #f1f5f9; }
.brand { font-size: 17px; font-weight: 800; color: #1e293b; }
.close-btn { width: 30px; height: 30px; border-radius: 7px; border: 1px solid #e2e8f0; background: none; color: #94a3b8; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.close-btn:hover { background: #f8fafc; color: #1e293b; }
.drawer-nav { flex: 1; padding: 10px 8px; overflow-y: auto; display: flex; flex-direction: column; gap: 1px; }
.nav-item { display: flex; align-items: center; gap: 10px; padding: 9px 10px; font-size: 13px; font-weight: 500; color: #475569; text-decoration: none; border-radius: 8px; transition: background 0.1s, color 0.1s; }
.nav-item:hover { background: #f8fafc; color: #1e293b; }
.nav-item.active { background: #eef2ff; color: #6366f1; font-weight: 600; }
.nav-item .badge { margin-left: auto; font-size: 10px; font-weight: 700; background: #6366f1; color: #fff; border-radius: 10px; padding: 1px 6px; }
.nav-section { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; color: #94a3b8; padding: 10px 10px 4px; margin-top: 6px; }
.drawer-footer { padding: 14px 16px; border-top: 1px solid #f1f5f9; }
.user-pill { display: flex; align-items: center; gap: 10px; }
.user-av { width: 34px; height: 34px; border-radius: 50%; background: linear-gradient(135deg,#6366f1,#8b5cf6); color: #fff; font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.user-name { font-size: 13px; font-weight: 600; color: #1e293b; }
.user-role { font-size: 11px; color: #94a3b8; }function openDrawer() { document.getElementById('drawer').classList.add('open'); document.getElementById('overlay').classList.add('show'); }
function closeDrawer() { document.getElementById('drawer').classList.remove('open'); document.getElementById('overlay').classList.remove('show'); }
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeDrawer(); });Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Side Drawer — translateX Slide-In, Overlay Backdrop & Three Close Mechanisms

A side drawer (also called a slide-over or off-canvas panel) slides in from the edge of the screen to show secondary content — filters, settings, navigation, or form details — without navigating away from the current page. Used in mobile navigation, filter panels, and settings sheets — see also the dual nav-and-settings drawer.
The slide-in animation
The drawer has position: fixed; right: 0; top: 0; bottom: 0; transform: translateX(100%) by default — positioned off the right edge of the screen. Adding .open transitions to translateX(0) with transition: transform 0.3s ease. This slides the drawer in from the right.
Three close mechanisms
The X button calls closeDrawer(). The overlay background has onclick="closeDrawer()". A keydown listener closes on Escape. All three call the same function that removes .open from the drawer and .show from the overlay.
The overlay
The overlay is a fixed full-screen div with a semi-transparent background. It shows behind the drawer and blocks interaction with the main content. The opacity transition (0 to 0.5) creates the dimming effect.
The translateX slide animation
Left drawers start at transform: translateX(-100%) — fully off-screen to the left. Adding .open transitions to translateX(0). The cubic-bezier spring curve (fast start, slow settle) creates the feel of a native mobile sheet opening. The CSS transition handles both open and close — removing .open reverses the animation automatically.
Backdrop and z-index layering
The backdrop is position: fixed; inset: 0 with a z-index below the drawer. When .open is applied, the backdrop fades in with opacity and gains pointer-events: all so clicks on it close the drawer. This click-backdrop-to-close is expected behaviour on all mobile UIs.
Push vs overlay mode
This snippet implements overlay mode — the drawer slides over the content with a backdrop. For push mode (content shifts right when drawer opens), add transition: margin-left 0.3s to the main content and set margin-left: 280px when the drawer opens. Overlay communicates temporary context; push communicates a persistent workspace panel.
Focus management for accessibility
When the drawer opens, move focus to the first focusable element inside: drawer.querySelector('a, button, input').focus(). On close, return focus to the element that triggered the open. This prevents keyboard users from losing their position on the page behind the drawer.
The translateX slide animation
Left drawers start at transform: translateX(-100%) — fully off-screen to the left. Adding .open transitions to translateX(0). The cubic-bezier spring curve (fast start, slow settle) creates the feel of a native mobile sheet opening. The CSS transition handles both open and close — removing .open reverses the animation automatically.
Backdrop and z-index layering
The backdrop is position: fixed; inset: 0 with a z-index below the drawer. When .open is applied, the backdrop fades in with opacity and gains pointer-events: all so clicks on it close the drawer. This click-backdrop-to-close is expected behaviour on all mobile UIs.
Push vs overlay mode
This snippet implements overlay mode — the drawer slides over the content with a backdrop. For push mode (content shifts right when drawer opens), add transition: margin-left 0.3s to the main content and set margin-left: 280px when the drawer opens. Overlay communicates temporary context; push communicates a persistent workspace panel.
Focus management for accessibility
When the drawer opens, move focus to the first focusable element inside: drawer.querySelector('a, button, input').focus(). On close, return focus to the element that triggered the open. This prevents keyboard users from losing their position on the page behind the drawer.
Step by step
How to Use
- 1Click Open drawerClick the button to slide the drawer in from the right. Click the overlay, the × button, or press ESC to close.
- 2Update drawer contentIn the HTML panel, change the drawer heading, description, and any form fields or links inside.
- 3Change drawer widthUpdate width: 320px on .drawer in the CSS panel.
- 4Change slide directionChange translateX(100%) to translateX(-100%) for a left-side drawer, and update right: 0 to left: 0.
- 5Connect close to form submissionCall closeDrawer() after a successful form submit or action completion.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The drawer has position: fixed; right: 0; transform: translateX(100%) by default — positioned at the right edge but shifted 100% of its own width off-screen. Adding .open transitions to translateX(0) with transition: transform 0.3s ease.
Change right: 0 to left: 0 on .drawer. Change translateX(100%) to translateX(-100%). Change the transform-origin if needed. Everything else is identical.
In openDrawer(), add document.body.style.overflow = "hidden". In closeDrawer(), restore it: document.body.style.overflow = "".
On openDrawer(), get all focusable elements in the drawer: const focusable = drawer.querySelectorAll("button, input, a"). Focus the first one. Add a keydown Tab handler that cycles within the drawer.
Yes. Click "JSX" for a React component. Manage isOpen in useState. Apply the CSS class conditionally: className={isOpen ? "drawer open" : "drawer"}. Use useEffect to add/remove the ESC keydown listener.
Add a CSS animation to the drawer content that triggers when .open is applied: .drawer.open .drawer-content { animation: slideUp 0.3s ease 0.1s both }. The 0.1s delay starts the content animation after the drawer begins sliding in.
Yes. While the Side Drawer snippet gives you one pattern to copy, the free Responsive Navbar Builder at webdevpuneet.com/navbar-builder/ designs a whole navigation bar: logo, links and dropdown menus, a mobile hamburger menu (dropdown panel, slide-in drawer or full screen) and a scroll effect (sticky, shrink, hide on scroll or transparent). It has six presets, a live preview that runs the real code, and exports HTML + CSS + vanilla JS, React, Tailwind, Vue 3 or Angular — or you can click Fork & Edit to keep editing it in My Code.