useElementSize()

This hook helps you to dynamically recover the width and the height of an HTML element. Dimensions are updated on load, on mount/un-mount, when resizing the window and when the ref changes.

The Hook

1import { useCallback, useState } from 'react'
2
3// See: https://usehooks-ts.com/react-hook/use-event-listener
4import { useEventListener } from '../useEventListener'
5// See: https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect
6import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'
7
8interface Size {
9 width: number
10 height: number
11}
12
13function useElementSize<T extends HTMLElement = HTMLDivElement>(): [
14 (node: T | null) => void,
15 Size,
16] {
17 // Mutable values like 'ref.current' aren't valid dependencies
18 // because mutating them doesn't re-render the component.
19 // Instead, we use a state as a ref to be reactive.
20 const [ref, setRef] = useState<T | null>(null)
21 const [size, setSize] = useState<Size>({
22 width: 0,
23 height: 0,
24 })
25
26 // Prevent too many rendering using useCallback
27 const handleSize = useCallback(() => {
28 setSize({
29 width: ref?.offsetWidth || 0,
30 height: ref?.offsetHeight || 0,
31 })
32
33 // eslint-disable-next-line react-hooks/exhaustive-deps
34 }, [ref?.offsetHeight, ref?.offsetWidth])
35
36 useEventListener('resize', handleSize)
37
38 useIsomorphicLayoutEffect(() => {
39 handleSize()
40 // eslint-disable-next-line react-hooks/exhaustive-deps
41 }, [ref?.offsetHeight, ref?.offsetWidth])
42
43 return [setRef, size]
44}
45
46export default useElementSize

Usage

1import React, { useState } from 'react'
2
3import { useElementSize } from 'usehooks-ts'
4
5export default function Component() {
6 const [isVisible, setVisible] = useState(true)
7 const [squareRef, { width, height }] = useElementSize()
8
9 const toggleVisibility = () => setVisible(x => !x)
10
11 return (
12 <>
13 <p>{`The square width is ${width}px and height ${height}px`}</p>
14 <p>Try, resize your window and-or click on the button.</p>
15
16 <button onClick={toggleVisibility}>
17 {isVisible ? 'Hide' : 'Show'} square
18 </button>
19
20 {isVisible && (
21 <div
22 ref={squareRef}
23 style={{
24 width: '50%',
25 paddingTop: '50%',
26 backgroundColor: 'aquamarine',
27 margin: 'auto',
28 }}
29 />
30 )}
31 </>
32 )
33}

Edit on CodeSandbox

See a way to make this page better?
Edit there »