UI

Drawer

Variant of the Dialog component. Display content as an overlay area at the right side of the screen.

Installation

  1. 1

    Add required components:

    Please add the Button component to use the Drawer.
  2. 2

    Install dependencies:

    npm install @radix-ui/react-dialog
  3. 3

    Add component:

    Copy and paste the code into your project’s component directory. Do not forget to update the import paths.
    // Tremor Drawer [v0.0.1]
    import * as React from "react"import * as DrawerPrimitives from "@radix-ui/react-dialog"import { RiCloseLine } from "@remixicon/react"
    import { cx, focusRing } from "@/lib/utils"
    import { Button } from "./Button"
    const Drawer = (  props: React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Root>,) => {  return <DrawerPrimitives.Root tremor-id="tremor-raw" {...props} />}Drawer.displayName = "Drawer"
    const DrawerTrigger = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Trigger>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Trigger>>(({ className, ...props }, ref) => {  return (    <DrawerPrimitives.Trigger ref={ref} className={cx(className)} {...props} />  )})DrawerTrigger.displayName = "Drawer.Trigger"
    const DrawerClose = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Close>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Close>>(({ className, ...props }, ref) => {  return (    <DrawerPrimitives.Close ref={ref} className={cx(className)} {...props} />  )})DrawerClose.displayName = "Drawer.Close"
    const DrawerPortal = DrawerPrimitives.Portal
    DrawerPortal.displayName = "DrawerPortal"
    const DrawerOverlay = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Overlay>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Overlay>>(({ className, ...props }, forwardedRef) => {  return (    <DrawerPrimitives.Overlay      ref={forwardedRef}      className={cx(        // base        "fixed inset-0 z-50 overflow-y-auto",        // background color        "bg-black/30",        // transition        "data-[state=closed]:animate-hide data-[state=open]:animate-dialogOverlayShow",        className,      )}      {...props}      style={{        animationDuration: "400ms",        animationFillMode: "backwards",      }}    />  )})
    DrawerOverlay.displayName = "DrawerOverlay"
    const DrawerContent = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Content>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Content>>(({ className, ...props }, forwardedRef) => {  return (    <DrawerPortal>      <DrawerOverlay>        <DrawerPrimitives.Content          ref={forwardedRef}          className={cx(            // base            "fixed inset-y-2 mx-auto flex w-[95vw] flex-1 flex-col overflow-y-auto rounded-md border p-4 shadow-lg focus:outline-none max-sm:inset-x-2 sm:inset-y-2 sm:right-2 sm:max-w-lg sm:p-6",            // border color            "border-gray-200 dark:border-gray-900",            // background color            "bg-white dark:bg-[#090E1A]",            // transition            "data-[state=closed]:animate-drawerSlideRightAndFade data-[state=open]:animate-drawerSlideLeftAndFade",            focusRing,            className,          )}          {...props}        />      </DrawerOverlay>    </DrawerPortal>  )})
    DrawerContent.displayName = "DrawerContent"
    const DrawerHeader = React.forwardRef<  HTMLDivElement,  React.ComponentPropsWithoutRef<"div">>(({ children, className, ...props }, ref) => {  return (    <div      ref={ref}      className="flex items-start justify-between gap-x-4 border-b border-gray-200 pb-4 dark:border-gray-900"      {...props}    >      <div className={cx("mt-1 flex flex-col gap-y-1", className)}>        {children}      </div>      <DrawerPrimitives.Close asChild>        <Button          variant="ghost"          className="aspect-square p-1 hover:bg-gray-100 hover:dark:bg-gray-400/10"        >          <RiCloseLine className="size-6" aria-hidden="true" />        </Button>      </DrawerPrimitives.Close>    </div>  )})
    DrawerHeader.displayName = "Drawer.Header"
    const DrawerTitle = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Title>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Title>>(({ className, ...props }, forwardedRef) => (  <DrawerPrimitives.Title    ref={forwardedRef}    className={cx(      // base      "text-base font-semibold",      // text color      "text-gray-900 dark:text-gray-50",      className,    )}    {...props}  />))
    DrawerTitle.displayName = "DrawerTitle"
    const DrawerBody = React.forwardRef<  HTMLDivElement,  React.ComponentPropsWithoutRef<"div">>(({ className, ...props }, ref) => {  return <div ref={ref} className={cx("flex-1 py-4", className)} {...props} />})DrawerBody.displayName = "Drawer.Body"
    const DrawerDescription = React.forwardRef<  React.ElementRef<typeof DrawerPrimitives.Description>,  React.ComponentPropsWithoutRef<typeof DrawerPrimitives.Description>>(({ className, ...props }, forwardedRef) => {  return (    <DrawerPrimitives.Description      ref={forwardedRef}      className={cx("text-gray-500 dark:text-gray-500", className)}      {...props}    />  )})
    DrawerDescription.displayName = "DrawerDescription"
    const DrawerFooter = ({  className,  ...props}: React.HTMLAttributes<HTMLDivElement>) => {  return (    <div      className={cx(        "flex flex-col-reverse border-t border-gray-200 pt-4 sm:flex-row sm:justify-end sm:space-x-2 dark:border-gray-900",        className,      )}      {...props}    />  )}
    DrawerFooter.displayName = "DrawerFooter"
    export {  Drawer,  DrawerBody,  DrawerClose,  DrawerContent,  DrawerDescription,  DrawerFooter,  DrawerHeader,  DrawerTitle,  DrawerTrigger,}
    
  4. 3

    Update tailwind.config.ts

    import type { Config } from 'tailwindcss';export default {  // ...  theme: {    extend: {      keyframes: {        drawerSlideLeftAndFade: {          from: { opacity: "0", transform: "translateX(100%)" },          to: { opacity: "1", transform: "translateX(0)" },        },        drawerSlideRightAndFade: {          from: { opacity: "1", transform: "translateX(0)" },          to: { opacity: "0", transform: "translateX(100%)" },        },      },      animation: {        // Drawer        drawerSlideLeftAndFade:        "drawerSlideLeftAndFade 150ms cubic-bezier(0.16, 1, 0.3, 1)",        drawerSlideRightAndFade: "drawerSlideRightAndFade 150ms ease-in",      },    },  },  // ...} satisfies Config;

Example

TitleAuthorYearActions
Twenty Thousand Leagues Under the SeaJules Verne1870
Journey to the Center of the EarthJules Verne1864
Around the World in Eighty DaysJules Verne1873
The Mysterious IslandJules Verne1874

API Reference: Drawer

This component uses the Radix UI API.

API Reference: DrawerTrigger

This component uses the Radix UI API.

API Reference: DrawerContent

This component uses the Radix UI API.

API Reference: DrawerHeader

This component is based on the div element and supports all of its props.

API Reference: DrawerTitle

This component uses the Radix UI API.

API Reference: DrawerBody

This component is based on the div element and supports all of its props.

API Reference: DrawerDescription

This component uses the Radix UI API.

API Reference: DrawerFooter

This component is based on the div element and supports all of its props.

API Reference: DrawerClose

This component uses the Radix UI API.