Drawer — Free HTML CSS JS Navigation Panel Snippet

Side Drawer · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Left navigation drawer: brand, nav items with SVG icons, active state, divider, user footer
Right settings panel: labeled toggle switches using hidden checkbox + CSS slider pattern
Slide animation: translateX(-100%/100%) → 0 via cubic-bezier(0.32,0.72,0,1) spring curve
Backdrop: rgba fade in sync with drawer, click-to-close
ESC keydown close: listener added on open, removed on close — no memory leak
open(side) function accepts "left" or "right" — shared close() closes all drawers
Toggle switches: pure CSS :checked selector — no JavaScript for toggle state
role="dialog" aria-modal="true" on both drawers

About this UI Snippet

Side Drawer — Left Navigation Drawer and Right Settings Panel with Slide Animation & Backdrop

Screenshot of the Side Drawer snippet rendered live

A side drawer is a panel that slides in from the left or right edge of the screen when triggered, overlaying the main content with a semi-transparent backdrop. It is more prominent than a dropdown menu and less disruptive than a full modal — the standard pattern for navigation drawers on mobile web apps, settings panels in desktop apps, and secondary content panels in dashboards. This snippet provides both a left navigation drawer and a right settings panel with shared open/close logic, backdrop, ESC key support, and cubic-bezier slide animation.

The slide animation

Both drawers start at transform: translateX(-100%) (left) and translateX(100%) (right) — fully off-screen. Adding the .open class changes the transform to translateX(0). The CSS transition uses cubic-bezier(0.32, 0.72, 0, 1) — a spring-like curve with fast start and slow decelerate, matching iOS sheet physics. The backdrop simultaneously fades from transparent to rgba(0,0,0,0.35).

Left navigation drawer

The left drawer contains an application brand, a nav list with SVG icons and an active item indicator (indigo background on .active), a divider, and a user footer with gradient avatar initials. This is the standard mobile navigation pattern — the nav items are links to main app sections.

Right settings panel

The right drawer contains four setting rows, each with a label and a CSS toggle switch. The toggle uses the standard hidden checkbox + slider pattern: the checkbox state controls the slider background colour and knob position via :checked selectors. No JavaScript needed for the toggle switches — they work natively as checkboxes.

Shared open/close logic

The open(side) function accepts 'left' or 'right' as a parameter and adds .open to the matching drawer and backdrop. The close() function removes .open from all drawers and the backdrop simultaneously — so opening the left drawer and then clicking the backdrop closes it correctly. ESC key calls close() via a document keydown listener that is added on open and removed on close.

Accessibility

Both drawers use role="dialog" and aria-modal="true". For full focus trapping (required for WCAG 2.1 AA), add a focus trap — see the accessibility note in the FAQ. The drawer also supports a push-content layout: add margin-left: 280px to the main area and transition it in sync with the drawer — the standard desktop sidebar pattern.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing every class toggle yourself, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the shared closeDrawer() function safely closes whichever drawer is open without needing to know which side triggered it, and why the cubic-bezier(0.32, 0.72, 0, 1) curve on the transform transition reads as a spring rather than a linear slide. The same assistant can help you optimize it, for example checking whether the keydown listener being added and removed on every open/close cycle could ever leak if openDrawer is called twice in a row without a close between them. It's also useful for extending the drawer: ask it to add real focus trapping so Tab cycles only within the open panel, wire the settings toggles to localStorage so preferences persist across reloads, or convert the left drawer into a push layout that shifts the main content instead of overlaying it. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a slide-in side drawer system with both a left navigation panel and a right settings panel in plain HTML, CSS, and JavaScript with no library.

Requirements:
- Two drawer elements, one anchored to the left edge and one to the right, each starting fully off-screen via a CSS transform (translateX of -100% for the left, 100% for the right), transitioning to translateX(0) on a shared "open" class using a spring-like cubic-bezier easing curve, plus a full-screen backdrop element that fades in opacity in sync with whichever drawer opens.
- A single open function parameterized by which side to open (not two separate near-duplicate functions) that adds the open class to the matching drawer and the backdrop, and a single close function that removes the open class from every drawer and the backdrop regardless of which one is currently open, so closing never needs to know which side was active.
- Wire the backdrop's click event and every drawer's close button to call that same shared close function, and add a document-level Escape keydown listener that also calls it, but only while a drawer is actually open, adding the listener when a drawer opens and removing it when it closes so it never fires or leaks while both drawers are closed.
- Build the right drawer's settings toggles as real checkbox inputs paired with a CSS sibling-selector-driven slider (no JavaScript needed to visually reflect the checked state), so the toggle appearance is driven entirely by the native :checked pseudo-class.
- Mark both drawers with role="dialog" and aria-modal="true" for assistive technology, and structure the left drawer with a distinct header, scrollable navigation list, and a footer user section so it mirrors real dashboard navigation drawers.

Step by step

How to Use

  1. 1
    Click Menu or Settings to open each drawerMenu opens the left navigation drawer. Settings opens the right settings panel. Click the backdrop, the × button, or press ESC to close either drawer.
  2. 2
    Update the left nav linksEdit the .nav-item anchor texts and href values in the left drawer. Move the .active class to the item matching the current page. Each nav item has an inline SVG icon — swap the icon paths to match your navigation icons.
  3. 3
    Update the settings togglesEdit the .setting-row span labels for each setting. The input type="checkbox" handles state natively — add checked to pre-enable a setting. Wire onchange to your settings API or localStorage for persistence.
  4. 4
    Add the user info in the footerUpdate the .user-av initials, .user-name, and .user-role text in the left drawer footer. Replace .user-av with an img element for a real avatar photo: add object-fit:cover and keep the border-radius:50%.
  5. 5
    Adjust the drawer widthChange width: 280px on .drawer to any value. For a full-width mobile drawer, add @media (max-width:480px) { .drawer { width: 100%; } }. For a narrower icon-only drawer, reduce to 60px and hide the text labels.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component managing open state with useState and side with a string, or "Tailwind" for a Tailwind CSS version.

Real-world uses

Common Use Cases

Mobile navigation drawer for responsive web applications
The left navigation drawer is the standard mobile navigation pattern for apps with more than 5 sections. Trigger from a hamburger icon in the top app bar. The drawer slides over the content rather than pushing it, preserving the user's context on the current page.
Settings and preferences panel for desktop web apps
The right settings panel provides a secondary interface for user preferences, notification settings, and account options without navigating away from the main content. The CSS toggle switches need no JavaScript — they store state as checkbox values and can be read directly in a form submission.
Filter and facet panels for search and listing pages
Adapt the left drawer as a filter panel for product listings or search results — or use the purpose-built faceted filter sidebar. Replace nav items with filter groups (checkbox lists, range sliders, radio groups). The drawer stays open while the user adjusts filters, then closes when they click Apply.
Shopping cart and checkout side panel
Use the right drawer as a mini-cart panel that slides in when a product is added to the cart. Show line items, quantities, total, and a Checkout CTA. The drawer stays in context so users can continue browsing without navigating to a separate cart page.
Study the CSS-only toggle switch and spring animation curve
The toggle switches use no JavaScript — the :checked pseudo-class on the hidden input controls the slider appearance via CSS sibling selectors. The cubic-bezier spring animation curve demonstrates how custom easing creates physics-like motion without animation libraries.
Detail and contextual information panels for data tables
Open a right drawer when a user clicks a table row to show detailed record information. The drawer stays alongside the table, so the user can navigate back to the list without losing their place. This drawer-as-detail-panel pattern is used in Gmail, Outlook, and most CRM interfaces.

Got questions?

Frequently Asked Questions

The drawer starts off-screen at transform: translateX(-100%) for left or translateX(100%) for right. Adding the .open class changes transform to translateX(0). The CSS transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1) animates between these values. The cubic-bezier coordinates create a spring-like curve: the first control point (0.32, 0.72) causes fast initial acceleration, and the second (0, 1) causes slow final deceleration — matching the feel of native iOS sheet animations.

After opening the drawer, find all focusable elements inside: const focusable = drawer.querySelectorAll("a,button,input,[tabindex]"). Save the previously focused element: const prevFocus = document.activeElement. Focus the first element: focusable[0].focus(). On keydown Tab: if the last element is focused and Tab (not Shift+Tab), redirect focus to focusable[0]. On Shift+Tab from the first element, redirect to the last. On close, restore focus: prevFocus.focus().

Add onchange handlers to each checkbox: checkbox.addEventListener("change", () => { localStorage.setItem("setting_"+key, checkbox.checked); }). On page load, read each setting: const saved = localStorage.getItem("setting_"+key); if (saved !== null) checkbox.checked = saved === "true". For a server-side app, submit the settings form with a POST request and save to the user's account — the initial checked state is then rendered server-side.

Click "JSX" to download. Manage openSide state with useState<"left"|"right"|null>(null). Render the backdrop and drawers conditionally based on openSide. Apply the open CSS class: className={"drawer left" + (openSide === "left" ? " open" : "")}. Add a useEffect to attach and clean up the ESC keydown listener when openSide is not null. For the toggle switches, replace the native checkbox with controlled React inputs using useState for each setting.