Ganz
Ganz

Reputation: 97

Get width of child element passed using {children} in React

I have part of the following component:

export const Carousel = ({ children }: ICarousel) => {
  // ... code omitted for brevity

  const [childWidth, setChildWidth] = useState(0);
  const childRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (childRef.current) {
      setChildWidth(childRef.current.getBoundingClientRect().width);
    }
  }, [children]);

  return (
    <div
      className="flex transition-transform duration-500 ease-in-out"
      style={{ transform: `translateX(-${currentIndex * 100}%)` }}
    >
    {React.Children.map(children, (child, index) => (
        <div
        key={index}
        ref={index === 0 ? childRef : null} // assign ref only to first child
        className="flex w-full flex-shrink-0 justify-center"
        aria-hidden={index !== currentIndex}
        style={{ width: `${childWidth}px` }}
        >
        {child}
        </div>
    ))}
    </div>
  );
};

Currently I am getting the width of the containing <div> that wraps the {child} elements, however I want to get the width of the first item passed into {child}.

Is this possible? If so, help would appreciated, thanks!

Upvotes: 0

Views: 27

Answers (1)

Shashika Silva
Shashika Silva

Reputation: 228

Instead of assigning the ref to the outer wrapper , you should assign it to the actual first child inside your JSX.

import React, { useState, useEffect, useRef } from "react";

export const Carousel = ({ children }: ICarousel) => {
  const [childWidth, setChildWidth] = useState(0);
  const childRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (childRef.current) {
      setChildWidth(childRef.current.getBoundingClientRect().width);
    }
  }, [children]);

  return (
    <div
      className="flex transition-transform duration-500 ease-in-out"
      style={{ transform: `translateX(-${currentIndex * 100}%)` }}
    >
      {React.Children.map(children, (child, index) => {
        const isFirstChild = index === 0;
        return (
          <div
            key={index}
            className="flex w-full flex-shrink-0 justify-center"
            aria-hidden={index !== currentIndex}
            style={{ width: `${childWidth}px` }}
          >
            {React.cloneElement(child as React.ReactElement, {
              ref: isFirstChild ? childRef : null,
            })}
          </div>
        );
      })}
    </div>
  );
};

Upvotes: 0

Related Questions