ReactHustle

React: Get the Height and Width of an Element

Jasser Mark Arioste

Jasser Mark Arioste

 React: Get the Height and Width of an Element

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:

  1. Track the height and width of an element using basic react hooks
  2. Track the width of an element using a custom hook from usehooks-ts.
  3. 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:

React Get Height and Width of Element tutorial

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

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle