React: Get the Height and Width of an Element
Jasser Mark Arioste
In this tutorial, you'll learn how to get the height and width of elements or components in React.
The Problem #
Sometimes, we need to get the height and width of an element so that we can use that value in one way or another. However, sometimes it may not be too clear how to implement this.
Consider the code below:
import { useState } from "react"; export default function Component() { const [items, setItems] = useState<string[]>([]); return ( <main className="max-w-xl mx-auto"> <h1>React Height and Width Tutorial</h1> <div className="bg-green-500 w-full p-4"> <h2 className="text-lg">Element A</h2> {items.map((item) => ( <p>{item}</p> ))} <button className="bg-green-700 text-white w-full p-2" onClick={() => { const newItem = `item ${items.length + 1}`; setItems([newItem, ...items]); }} > Add item </button> </div> <div className="bg-indigo-500 text-white w-full p-4 absolute bottom-10 left-0"> <h2 className="text-lg">Element B</h2> <p> The height and width of this absolutely positioned element should match element A </p> </div> </main> ); }
123456789101112131415161718192021222324252627282930313233
Explanation: We want two elements to have the same width. However, Element B uses position:absolute
and cannot get the dimensions of its parent element.
Tutorial Objectives #
After this tutorial, you'll learn the following:
- Track the height and width of an element using basic react hooks
- Track the width of an element using a custom hook from usehooks-ts.
- Refactoring: Creating your own custom hook
Tracking Width and Height of Element #
To track the width and height of elements in React, we'll have to use a combination of basic React hooks. I added comments for the explanations
import { useLayoutEffect, useRef, useState } from "react"; export default function Component() { const [items, setItems] = useState<string[]>([]); // Step 1. create a reference to the element we want to track const ref = useRef<HTMLDivElement>(null); // Step 2. create a state to track the dimensions of the element const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); // Step 3. use useUseLayoutEffect over useEffect so that we update the dimensions after the dom has finished updating useLayoutEffect(() => { if (ref.current) { const { clientWidth, clientHeight } = ref.current; setDimensions({ width: clientWidth, height: clientHeight, }); } }, [items]); return ( <main className="max-w-xl mx-auto"> <h1>React Height and Width Tutorial</h1> {/* Step 4. assign the ref to the tracked element */} <div className="bg-green-500 w-full p-4" ref={ref}> <h2 className="text-lg">Element A</h2> {items.map((item) => ( <p>{item}</p> ))} <button className="bg-green-700 text-white w-full p-2" onClick={() => { const newItem = `item ${items.length + 1}`; setItems([newItem, ...items]); }} > Add item </button> </div> {/* Step 5. Assign the dimensions to the other element */} <div className="bg-indigo-500 text-white w-full p-4 absolute bottom-10 left-0" style={{ height: dimensions.height, width: dimensions.width }} > <h2 className="text-lg">Element B</h2> <p> The height and width of this absolutely positioned element should match element A </p> </div> </main> ); }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
Using useElementSize
from usehooks-ts
#
Another option to track the width and height of elements in react is to use the useElementSize hook from usehooks-ts package. First, let's install usehooks-ts
package using the following command:
yarn add usehooks-ts
1
Now, we can use this hook to track the size of our element:
import { useState } from "react"; import { useElementSize } from "usehooks-ts"; export default function Component() { const [items, setItems] = useState<string[]>([]); // Step 1. use the useElementSize hook. // this returns a ref and the dimensions/size object const [ref, size] = useElementSize(); return ( <main className="max-w-xl mx-auto"> <h1>React Height and Width Tutorial</h1> {/* Step 4. assign the ref to the tracked element */} <div className="bg-green-500 w-full p-4" ref={ref}> <h2 className="text-lg">Element A</h2> {items.map((item) => ( <p>{item}</p> ))} <button className="bg-green-700 text-white w-full p-2" onClick={() => { const newItem = `item ${items.length + 1}`; setItems([newItem, ...items]); }} > Add item </button> </div> {/* Step 5. Assign the size object to the other element */} <div className="bg-indigo-500 text-white w-full p-4 absolute bottom-10 left-0" style={{ height: size.height, width: size.width }} > <h2 className="text-lg">Element B</h2> <p> The height and width of this absolutely positioned element should match element A </p> </div> </main> ); }
123456789101112131415161718192021222324252627282930313233343536373839404142
Creating Your Own Custom Hook #
You can also create your own custom hook to clean up some code. First, create the file hooks/useElementSize.tsx
. Then, copy the code below:
// hooks/useElementSize.tsx import { DependencyList, MutableRefObject, useLayoutEffect, useRef, useState, } from "react"; type Dimensions = { height: number; width: number; }; // allow passing of dependencies to recompute height and width export const useElementSize = <T extends HTMLElement = HTMLDivElement>( deps: DependencyList ): [MutableRefObject<T | null>, Dimensions] => { const ref = useRef<T | null>(null); // Step 1. create a state to track the dimensions of the element const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); // Step 2. use useUseLayoutEffect over useEffect so that we update the dimensions after the dom has finished updating useLayoutEffect(() => { if (ref.current) { const { clientWidth, clientHeight } = ref.current; setDimensions({ width: clientWidth, height: clientHeight, }); } }, deps); // Step 3. Return ref and dimensions return [ref, dimensions]; };
123456789101112131415161718192021222324252627282930313233343536
Now, we can use our own custom hook to track the element size as seen below:
import { useElementSize } from "@/hooks/useElementSize"; import { useState } from "react"; export default function Component() { const [items, setItems] = useState<string[]>([]); // Step 1: use custom hook const [ref, dimensions] = useElementSize([items]); return ( <main className="max-w-xl mx-auto"> <h1>React Height and Width Tutorial</h1> {/* Step 2. assign the ref to the tracked element */} <div className="bg-green-500 w-full p-4" ref={ref}> <h2 className="text-lg">Element A</h2> {items.map((item) => ( <p>{item}</p> ))} <button className="bg-green-700 text-white w-full p-2" onClick={() => { const newItem = `item ${items.length + 1}`; setItems([newItem, ...items]); }} > Add item </button> </div> {/* Step 3. Assign the dimensions to the other element */} <div className="bg-indigo-500 text-white w-full p-4 absolute bottom-10 left-0" style={{ height: dimensions.height, width: dimensions.width }} > <h2 className="text-lg">Element B</h2> <p> The height and width of this absolutely positioned element should match element A </p> </div> </main> ); }
1234567891011121314151617181920212223242526272829303132333435363738394041
Demo #
Here's the final output. Notice how the height of element B updates as we add items:
Conclusion #
You learned three ways to track the height and width of elements in React. Now it's up to you which way you choose.
References #
Credits: Image by Leslin_Liu from Pixabay