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