useElementSize

Layout/Viewport

A React hook that tracks element dimensions in real-time using ResizeObserver, perfect for responsive layouts and dynamic UI adjustments.

Demo

Try resizing the container below to see how elements adapt to the available space:

Container Width
0px
Container Height
0px
Font size: 16px

Responsive Text

This text block smoothly fades and scales based on container width.

1
2
3
4
Grid Columns
1
Scale
0.00
Opacity
-1.00
Tip: Drag the right edge of the container to resize it.

Installation

npm install @thibault.sh/hooks

Usage

import { useElementSize } from '@thibault.sh/hooks/useElementSize';
import { useRef } from 'react';

function ResponsiveElement() {
  const elementRef = useRef<HTMLDivElement>(null);
  const { width, height } = useElementSize(elementRef);

  return (
    <div ref={elementRef} className="resize overflow-auto p-4 border">
      <div>Width: {Math.round(width)}px</div>
      <div>Height: {Math.round(height)}px</div>
      {/* Content */}
    </div>
  );
}

API

Returns

Object containing current element width and height

Features

  • Real-time Updates

    Automatically updates when element dimensions change using ResizeObserver

  • Performance Optimized

    Uses efficient ResizeObserver API with proper cleanup

  • Zero Layout Shift

    Measures content size without affecting layout

  • SSR Compatible

    Safely handles server-side rendering scenarios

Responsive Grid Example

import { useElementSize } from '@thibault.sh/hooks/useElementSize';
import { useRef } from 'react';

function ResponsiveGrid({ items }: { items: Array<any> }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const { width } = useElementSize(containerRef);

  // Calculate optimal number of columns based on container width
  const columns = Math.max(1, Math.floor(width / 300)); // 300px min column width

  return (
    <div ref={containerRef} className="w-full">
      <div
        className="grid gap-4"
        style={{ gridTemplateColumns: `repeat(${columns}, 1fr)` }}
      >
        {items.map((item, index) => (
          <div key={index} className="p-4 border rounded">
            {/* Item content */}
          </div>
        ))}
      </div>
    </div>
  );
}

Dynamic Text Sizing Example

import { useElementSize } from '@thibault.sh/hooks/useElementSize';
import { useRef } from 'react';

function ResponsiveText() {
  const containerRef = useRef<HTMLDivElement>(null);
  const { width } = useElementSize(containerRef);

  // Scale font size based on container width
  const fontSize = Math.max(16, Math.min(width / 20, 48));

  return (
    <div ref={containerRef} className="w-full resize overflow-auto p-4 border">
      <p style={{ fontSize: `${fontSize}px` }}>
        This text will scale with the container width!
      </p>
    </div>
  );
}

Aspect Ratio Container Example

import { useElementSize } from '@thibault.sh/hooks/useElementSize';
import { useRef, useEffect, useState } from 'react';

function AspectRatioContainer({ ratio = 16 / 9 }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const { width } = useElementSize(containerRef);
  const [height, setHeight] = useState(0);

  useEffect(() => {
    setHeight(width / ratio);
  }, [width, ratio]);

  return (
    <div ref={containerRef} className="w-full">
      <div
        style={{ height: `${height}px` }}
        className="bg-gray-100 transition-all duration-200"
      >
        {/* Content that maintains aspect ratio */}
      </div>
    </div>
  );
}