#492·vaul

Controlled drawer with `modal={false}` does not work because of bug in `useControllableState`

Author: skirstenCreated Oct 19, 2024Updated Aug 12, 2026

This took me a while to trace down, but basically a Drawer that is controlled and has modal false e.g.:

typescript
const [open, setOpen] = useState(false);

return (
  <>
    <Drawer open={open} onOpenChange={setOpen} modal={false}>
      {/* ... */}
    </Drawer>
    {/* Button somewhere else outside */}
    <Button onClick={() => setOpen(true)}>Open</Button>
  </>
);

and open is set from somewhere outside, it does not get to this line to hack the pointerEvents:

https://github.com/emilkowalski/vaul/blob/504102918ed53d5037c694b2f3300825b4e2f3fb/src/index.tsx#L187

because if the prop changes it does not get to this line to call the handleChange function here: https://github.com/emilkowalski/vaul/blob/504102918ed53d5037c694b2f3300825b4e2f3fb/src/use-controllable-state.ts#L50

So to conclude, under these circumstances it will not remove the pointerEvents = "none" :cry:

Also I am curious why these awful hacks with the pointerEvents are necessary instead of just setting modal={false} on the DialogPrimitive.Root? Maybe this would break something else?