Drawer (and possibly Modal) does not account for on-screen keyboard on mobile
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 6.9k
- Forks
- 1.1k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 57
Description
Description
When Drawer is opened on a mobile device and a focused input triggers the on-screen keyboard, the drawer content does not adjust its height or position. Instead, the body appears to keep the height of the original viewport rather than resizing to the new visual viewport height once the keyboard is shown, so content and inputs near the bottom can end up hidden behind the keyboard. This can be especially disruptive for bottom-anchored drawers (direction="bottom") used for forms, chat inputs, or search fields.
The same issue may also affect Modal, though this hasn't been confirmed yet, it's possible both components share the same underlying gap in keyboard handling.
Steps to reproduce
- Open a
Drawerwithdirection="bottom"containing a text input near the bottom of the content. - Open it on a mobile device (or emulate one).
- Focus the input to trigger the on-screen keyboard.
- Observe that the body/content area keeps its original viewport height instead of shrinking to the visual viewport, and the drawer does not reposition to stay above the keyboard.
- (To check) Repeat with
Modalto see if it exhibits the same behavior.
Expected behavior
The drawer (and modal, if affected) should track the actual visible viewport height once the keyboard is open, resizing or repositioning its content so focused inputs remain visible above the keyboard rather than being covered by it.
Suggested approach
Pure Web Bottom Sheet (live demo) handles this well with a layered strategy that could be a useful reference:
- Use the VirtualKeyboard API where supported, reading the
keyboard-inset-bottomCSS environment variable to adjust height/margin. - Fall back to
interactive-widget=resizes-contenton the viewport meta tag for browsers without VirtualKeyboard API support. - On iOS Safari (which supports neither), listen to
window.visualViewportresize events and expose the keyboard height as a CSS custom property.
Note that interactive-widget=resizes-content is a page-wide viewport setting, not something tied to native <dialog> elements, so it should apply regardless of markup. But it only shrinks the layout viewport itself: elements positioned with position: fixed (which is how vaul-vue, en dus Drawer, positions its content) don't automatically follow that resize unless the component also reacts to it (e.g. via 100dvh/100svh or the VirtualKeyboard API). So the meta tag alone likely isn't sufficient here; Drawer's own sizing logic would need to respond to the new viewport height as well.
Since Drawer is built on vaul-vue, this may need to be handled either upstream in vaul-vue or with a Nuxt UI-specific wrapper. It's worth checking whether Modal shares the same content-sizing logic, in which case a fix might apply to both.
Additional context
- Nuxt UI Drawer source: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Drawer.vue
- Reference implementation: https://viliket.github.io/pure-web-bottom-sheet/chat/
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/runtime/components/Drawer.vue and inspect how its vaul-vue content is sized and positioned. Reproduce the issue on a mobile device or emulator with a bottom drawer and focused input, then compare the behavior with Modal and the visual viewport. Done means focused inputs remain visible above the on-screen keyboard, with the affected component behavior verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100