useElementSize
This hook has been deprecated, use useResizeObserver() instead.
Example
import { useState } from 'react'
import { useElementSize } from 'usehooks-ts'
export default function Component() {
const [isVisible, setVisible] = useState(true)
const [squareRef, { width = 0, height = 0 }] = useElementSize()
const toggleVisibility = () => {
setVisible(x => !x)
}
return (
<>
<p>{`The square width is ${width}px and height ${height}px`}</p>
<p>Try, resize your window and-or click on the button.</p>
<button onClick={toggleVisibility}>
{isVisible ? 'Hide' : 'Show'} square
</button>
{isVisible && (
<div
ref={squareRef}
style={{
width: '50%',
paddingTop: '50%',
backgroundColor: 'aquamarine',
margin: 'auto',
}}
/>
)}
</>
)
}
Hook
import { useCallback, useState } from 'react'
import { useEventListener, useIsomorphicLayoutEffect } from 'usehooks-ts'
type Size = {
width: number | undefined
height: number | undefined
}
type UseElementSizeOptions = {
initializeWithValue?: boolean
}
/** Supports both array and object destructing */
type UseElementSizeResult = [(node: Element | null) => void, Size] &
(Size & { ref: (node: Element | null) => void })
/**
* @deprecated - Use `useResizeObserver` instead.
* A hook for tracking the size of a DOM element.
* @template T - The type of the DOM element. Defaults to `HTMLDivElement`.
* @param {?UseElementSizeOptions} [options] - The options for customizing the behavior of the hook (optional).
* @param {?boolean} [options.initializeWithValue] - If `true` (default), the hook will initialize reading the element's size. In SSR, you should set it to `false`.
* @returns The ref-setting function and the size of the element. Either as an tuple [ref, size] or as an object { ref, width, height }.
* @see [Documentation](https://usehooks-ts.com/react-hook/use-element-size)
* @example
* const [ref, { width = 0, height = 0 }] = useElementSize();
* // or
* const { ref, width = 0, height = 0 } = useElementSize();
*
* return (
* <div ref={ref}>
* My size is {size.width}x{size.height}
* </div>
* );
*/
export function useElementSize<T extends HTMLElement = HTMLDivElement>(
options: UseElementSizeOptions = {},
): UseElementSizeResult {
const { initializeWithValue = true } = options
// Mutable values like 'ref.current' aren't valid dependencies
// because mutating them doesn't re-render the component.
// Instead, we use a state as a ref to be reactive.
const [ref, setRef] = useState<T | null>(null)
const readValue = useCallback<() => Size>(() => {
return {
width: ref?.offsetWidth ?? undefined,
height: ref?.offsetHeight ?? undefined,
}
}, [ref?.offsetHeight, ref?.offsetWidth])
const [size, setSize] = useState<Size>(() => {
if (initializeWithValue) {
return readValue()
}
return { width: undefined, height: undefined }
})
// Prevent too many rendering using useCallback
const handleSize = useCallback(() => {
setSize(readValue())
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref?.offsetHeight, ref?.offsetWidth])
// TODO: Prefer incoming useResizeObserver hook
useEventListener('resize', handleSize)
useIsomorphicLayoutEffect(() => {
handleSize()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref?.offsetHeight, ref?.offsetWidth])
const result = [setRef, size] as UseElementSizeResult
// Support object destructuring
result.ref = result[0]
result.width = size.width
result.height = size.height
return result
}