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