useVisualViewportHeight.ts raw
1 import { useEffect, useRef, useState } from 'react'
2
3 /**
4 * Hook that tracks the visual viewport height, adjusting for software keyboard
5 * and browser chrome changes. Returns the current viewport height and a ref
6 * callback to attach to the container element.
7 *
8 * Falls back to window.innerHeight when visualViewport API is unavailable.
9 */
10 export function useVisualViewportHeight() {
11 const [height, setHeight] = useState(() =>
12 window.visualViewport?.height ?? window.innerHeight
13 )
14 const rafRef = useRef<number>(0)
15
16 useEffect(() => {
17 const viewport = window.visualViewport
18 if (!viewport) return
19
20 const update = () => {
21 cancelAnimationFrame(rafRef.current)
22 rafRef.current = requestAnimationFrame(() => {
23 setHeight(viewport.height)
24 })
25 }
26
27 viewport.addEventListener('resize', update)
28 update()
29
30 return () => {
31 viewport.removeEventListener('resize', update)
32 cancelAnimationFrame(rafRef.current)
33 }
34 }, [])
35
36 return height
37 }
38