Skip to content

Instantly share code, notes, and snippets.

@MartijnHols
Last active July 16, 2024 21:57
Show Gist options
  • Save MartijnHols/e9f4f787efa9190885a708468f63c5bb to your computer and use it in GitHub Desktop.
Save MartijnHols/e9f4f787efa9190885a708468f63c5bb to your computer and use it in GitHub Desktop.
React hooks for getting the document height that updates when the On Screen Keyboard/Virtual Keyboard toggles
The latest version is available at https://martijnhols.nl/gists/how-to-get-document-height-ios-safari-osk
import { useEffect } from 'react'
const useOnScreenKeyboardScrollFix = () => {
useEffect(() => {
const handleScroll = () => {
window.scrollTo(0, 0)
}
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
}
export default useOnScreenKeyboardScrollFix
@komagroup
Copy link

komagroup commented Jun 28, 2024

I have added this line

useEffect(() => {
    window.scrollTo(0, 0)
  }, [viewportHeight]);

So it always scrolls to 0 if the viewportHeight changes but it also doesnt work.
Browser is standard android google chrome btw

@MartijnHols
Copy link
Author

You might need a few timeouts like I did in the useViewportSize hook, but that will be kind of ugly for the user. Luckily it will only be ugly for the crazy browsers.

      // Closing the OSK in iOS does not immediately update the visual viewport
      // size :<
      setTimeout(updateViewportSize, 1000)

One nice thing is that since you're setting scroll position to 0 every time, you can fairly easily start multiple timeouts without the user noticing.

@komagroup
Copy link

komagroup commented Jun 28, 2024

It seems to work if I adjust the maxHeight instead of the height and it has a h-full class from tailwind ( which is just height:100% )

import { ElementType, HTMLAttributes } from "react";
import useViewportSize from "@/hooks/useViewportSize";
import useOnScreenKeyboardScrollFix from "@/hooks/useOnScreenKeyboardScrollFix";
import usePreventOverScrolling from "@/hooks/usePreventOverScrolling";
import useIsOnScreenKeyboardOpen from "@/hooks/useOnScreenKeyboardOpen";

interface Props extends HTMLAttributes<HTMLDivElement> {
  element?: ElementType;
}

export function FullViewportContainer({
  element: Element = "div",
  ...others
}: Props) {
  useOnScreenKeyboardScrollFix();
  const [, viewportHeight] = useViewportSize()  ?? [];
  const ref = usePreventOverScrolling();
  const isOnScreenKeyboardOpen = useIsOnScreenKeyboardOpen();
  return (
    <Element
      {...others}
      ref={ref}
      className="w-full h-full"
      style={{
        maxHeight: viewportHeight,
        padding: isOnScreenKeyboardOpen
          ? "env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left)"
          : "env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)",
        transition: "padding 100ms, height 100ms",
      }}
    />
  );
}

Aaaand it must be the direct children of the root it seems

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment