Skip to content

Instantly share code, notes, and snippets.

@mustafadalga
Created November 28, 2025 18:10
Show Gist options
  • Select an option

  • Save mustafadalga/85909f1d8315ff73e2239f996f9516fd to your computer and use it in GitHub Desktop.

Select an option

Save mustafadalga/85909f1d8315ff73e2239f996f9516fd to your computer and use it in GitHub Desktop.
Animated drawer component in React.js
import Drawer from "./components/Drawer.tsx";
import { useAnimatedToggle } from "./hooks/useAnimatedToggle";
function App() {
const { isOpen, shouldRender, onEnd,toggle } = useAnimatedToggle();
return (
<div className='m-4'>
<button onClick={toggle}>toggle drawer {isOpen}</button>
{shouldRender && <Drawer isOpen={isOpen} onEnd={onEnd} />}
</div>
)
}
export default App
import { useEffect, useState } from "react";
export default function Drawer({ isOpen, onEnd }: {
isOpen: boolean,
onEnd: () => void
}) {
const [ mounted, setMounted ] = useState(false);
useEffect(() => {
setMounted(true);
}, [])
return (
<div
onTransitionEnd={onEnd}
className={`h-screen w-[22rem] fixed right-0 top-0 p-2 border-l bg-white transition-transform duration-300 data-[open=false]:translate-x-[22rem] data-[open=true]:translate-x-0`}
data-open={isOpen && mounted}>
{isOpen}
content
</div>
);
}
import { useCallback, useState } from "react";
export enum DrawerState {
Closed = 'closed',
Opening = 'opening',
Open = 'open',
Closing = 'closing'
}
export function useAnimatedToggle() {
const [state, setState] = useState<DrawerState>(DrawerState.Closed);
const toggle = useCallback(() => {
setState(s =>
s === DrawerState.Open ? DrawerState.Closing : DrawerState.Opening
);
}, []);
const onEnd = useCallback(() => {
setState(s =>
s === DrawerState.Opening ? DrawerState.Open : DrawerState.Closed
);
}, []);
return {
isOpen: state === DrawerState.Open || state === DrawerState.Opening,
shouldRender: state !== DrawerState.Closed,
toggle,
onEnd
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment