Drawer

components/Drawer.tsx
'use client'
import ReactDom from 'react-dom'
import { useEffect, useState } from 'react'
type Props = {
active: boolean
setActive: React.Dispatch<React.SetStateAction<boolean>>
children: string | JSX.Element | JSX.Element[]
}
export default function Drawer({ active, setActive, children }: Props) {
const [isVisible, setIsVisible] = useState(false)
const closeDrawer = () => {
setIsVisible(false)
setTimeout(() => {
setActive(false)
}, 300)
}
useEffect(() => {
if (active) {
setIsVisible(true)
}
}, [active])
if (!active) return null
return ReactDom.createPortal(
<div
role="dialog"
aria-modal="true"
data-visible={isVisible ? 'true' : 'false'}
onClick={closeDrawer}
className="fixed left-0 group top-0 z-50 flex h-[100dvh] data-[visible=true]:opacity-100 data-[visible=true]:visible data-[visible=false]:opacity-0 data-[visible=false]:invisible w-screen items-start justify-start bg-overlay transition-all duration-300"
>
<div
onClick={(e) => e.stopPropagation()}
className="z-10 h-full w-[250px] group-data-[visible=true]:translate-x-0 group-data-[visible=false]:translate-x-[-250px] border-2 border-border dark:border-darkBorder bg-main font-base transition-transform duration-300"
>
{children}
</div>
</div>,
document.getElementById('drawer') as HTMLElement,
)
}

Before using

You'll have to add <div id="drawer"></div> to your layout or index.html.


<div id="drawer"></div>

Usage

import { useState } from 'react'
import Button from '@/components/Button'
import Drawer from '@/components/Drawer'

const [isDrawerActive, setIsDrawerActive] = useState(false)

<>
<Button
onClick={() => {
setIsDrawerActive(true)
}}
>
Open Drawer
</Button>
<Drawer active={isDrawerActive} setActive={setIsDrawerActive}>
<a
className="block w-full text-text border-b-2 border-border dark:border-darkBorder bg-main px-5 py-4 hover:bg-mainAccent"
href="#"
>
Item 1
</a>
<a
className="block w-full text-text border-b-2 border-border dark:border-darkBorder bg-main px-5 py-4 hover:bg-mainAccent"
href="#"
>
Item 2
</a>
<a
className="block w-full text-text border-b-2 border-border dark:border-darkBorder bg-main px-5 py-4 hover:bg-mainAccent"
href="#"
>
Item 3
</a>
</Drawer>
</>