Skip to content
Template Empire / components

Search components

10 results

Browse components

Slide-Over Drawer

A free React slide-over drawer component built on the native dialog element, with a spring slide-in and staggered content reveal.

  • Automated axe check
  • Reduced-motion tested
  • SSR build verified
  • Motion
  • 2 runtime packages

Slide-Over Drawer is a free drawer component for React and Next.js, built with Motion and Tailwind on top of the native dialog element. Opening it fades in a blurred backdrop while a full-height panel glides in from the right or left edge on a soft spring, and once the panel is in flight its content rises into place with a 50 millisecond stagger. Because it uses showModal, the focus trap, top layer rendering and Escape handling come from the browser rather than from JavaScript re-implementations.

The component is fully controlled through open and onClose props, picks its entry edge with the side prop, locks background scroll while open, and never lets the exit animation delay focus: the moment the drawer closes, focus returns to the button that opened it. The visible title labels the drawer for screen readers, the close button is a real button with an accessible name, a click on the backdrop closes the drawer, and the staggered content is real DOM that assistive technology can read throughout the animation. With prefers-reduced-motion enabled there is no slide and no stagger; panel and content fade in over 150 milliseconds or less.

Details, one glide away

Slide-overs keep context on screen while secondary tasks get a full panel. Open the drawer to see the slide and content stagger.

Customise

Component settings update the preview and generated code together.

Install

Add the @te registry to your components.json once:

{
  "registries": {
    "@te": "https://templateempire.io/r/{name}.json"
  }
}

Then install the component:

npx shadcn@latest add @te/modal-drawer

Usage

"use client";

import { useState } from "react";
import { ModalDrawer } from "@/components/modal-drawer";

export default function Page() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button type="button" onClick={() => setOpen(true)}>
        Open drawer
      </button>
      <ModalDrawer
        open={open}
        onClose={() => setOpen(false)}
        title="Notification settings"
        side="right"
      >
        <p>Choose how the workspace reaches you.</p>
      </ModalDrawer>
    </>
  );
}

Props

PropTypeDefaultDescription
openbooleanrequiredControlled open state.
onClose() => voidrequiredCalled when the drawer asks to close: Escape, a click on the backdrop or the close button.
titlestringrequiredVisible h2 heading that names the drawer via aria-labelledby.
childrenReactNoderequiredDrawer body; direct children stagger on entry.
side"right" | "left""right"Edge the panel enters from.
classNamestringundefinedAdditional classes merged onto the panel.

Customisation

Slide-Over Drawer declares no tokens of its own; the panel and backdrop consume the global semantic tokens through Tailwind utilities, and the slide uses the shared springSoft preset from lib/motion.ts, so retuning that preset retunes every soft-spring component together. The className prop is merged onto the panel, which is the usual place to change its width or padding:

:root {
  --border: oklch(from var(--color-neutral-50) l c h / 0.16);
}

<ModalDrawer
  open={open}
  onClose={() => setOpen(false)}
  title="Notification settings"
  className="max-w-lg p-8"
>
  ...
</ModalDrawer>

Frequently asked questions

Is Slide-Over Drawer free for commercial use?
Yes. Slide-Over Drawer is MIT licensed, so you can use it in personal and commercial projects without attribution.
Is Slide-Over Drawer accessible for keyboard and screen reader users?
Yes. It renders a native dialog element opened with showModal, so the browser provides the focus trap, top layer rendering and Escape handling, and the page behind it becomes inert. The visible title labels the drawer through aria-labelledby, the close button is a real button named Close drawer, background scroll is locked while the drawer is open, and the staggered content is ordinary DOM that screen readers can read at any point during the animation. When the drawer closes, focus returns to the button that opened it immediately, never waiting for the exit animation.
How does the slide and stagger animation work, and what happens with reduced motion?
Motion animates only transform and opacity: the backdrop fades in over 300 milliseconds while the full-height panel slides from the chosen edge to rest on the shared springSoft preset, settling in about half a second. Once the panel is in flight its direct children rise 12 pixels into place with a 50 millisecond stagger that starts 0.15 seconds in, and closing slides the panel out over 0.25 seconds while the backdrop fades. With prefers-reduced-motion enabled the slide and stagger are dropped entirely and both panel and content become plain opacity fades of 150 milliseconds or less.

Related components

Want the full page this belongs to?Template Empire builds complete Next.js templates with this motion system throughout. Browse the paid templates that pair with these free components.Explore Template Empire templates