Skip to content

useContentSize ​

The size of an element's content box, in whole pixels, kept current with a ResizeObserver. useMeasuredWidth is the same for the width alone.

tsx
import { useContentSize, useMeasuredWidth } from '@basmilius/react-ui';
tsx
import { useState } from 'react';
import { useContentSize, useMeasuredWidth } from '@basmilius/react-ui';

export default function UseContentSizeDemo() {
    const [measure, size] = useContentSize();
    const [measureWidth, width] = useMeasuredWidth();
    const [wide, setWide] = useState(false);

    return (
        <div className="flex w-full flex-col items-center gap-3">
            <div
                ref={measure}
                className="grid h-24 place-items-center rounded-lg border border-dashed border-border-strong text-xs text-text-muted"
                style={{ width: wide ? '100%' : '50%' }}
            >
                {size.width} by {size.height}
            </div>
            <div ref={measureWidth} className="h-2 w-3/4 rounded-full bg-accent-soft">
                <div className="h-2 rounded-full bg-accent" style={{ width: Math.round(width * 0.4) }} />
            </div>
            <button type="button" className="focus-ring rounded-md text-xs text-accent" onClick={() => setWide(!wide)}>
                {wide ? 'Narrow the box' : 'Widen the box'}
            </button>
        </div>
    );
}

Both answer a callback ref and the size. Put the ref on the element to measure:

tsx
const [measure, { width, height }] = useContentSize();

return <div ref={measure}>{width > 0 && <Plot width={width} height={height} />}</div>;

The size is rounded, so a frame fitted into the space lands on whole pixels too. A chart that draws in real pixels, rather than stretching a view box, uses the width to keep every line sharp. The size is 0 by 0 until the element is there.

ContentSize ({ width, height }) is an exported type.