JonathanSvärdén

getBoundingClientRect and custom fonts

🕒 1 min read

This is a minor gotcha that you may run into when working with browser APIs like getBoundingClientRect.

If you want to perform calculations based on the exact position of an element whose size depends on its text content, you will find that you sometimes get an incorrect result when refreshing the page. After the page is fully loaded though, everything works as expected. So what's going on here?

useEffect(() => {
  const x = element.current.getBoundingClientRect().x; // wrong x position
})

This is caused by the fact that the element's position is calculated before your custom font has been applied to it. You can get around this by using the (as yet experimental) FontFaceSet API's ready method.

const [fontLoaded, setFontLoaded] = useState(false);

useEffect(() => {
  document.fonts.ready.then(() => {
    setFontLoaded(true);
  });
});

Then run the effect again when the font has loaded:

useEffect(() => {
  const x = element.current.getBoundingClientRect().x;
}, [fontLoaded]);

References

https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet

https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready