Measures an element's dimensions using ResizeObserver. Returns a ref callback and the current bounds.
Installation
npm install betteruseUsage
import { useMeasure } from 'betteruse'
function ResponsiveComponent() {
const [ref, bounds] = useMeasure()
return (
<div ref={ref}>
<p>Width: {bounds.width}px</p>
<p>Height: {bounds.height}px</p>
</div>
)
}
API Reference
useMeasure()
Returns a tuple of [ref, bounds].
ref
A callback ref to attach to the element you want to measure.
Bounds
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | - | Content width of the element |
height | number | - | Content height of the element |
top | number | - | Top position relative to viewport |
left | number | - | Left position relative to viewport |
right | number | - | Right position relative to viewport |
bottom | number | - | Bottom position relative to viewport |
x | number | - | X coordinate (same as left) |
y | number | - | Y coordinate (same as top) |
How It Works
- Creates a ResizeObserver when an element is attached
- Observes the element for size changes
- Updates bounds state on each resize
- Cleans up observer when element is removed or component unmounts
This hook is SSR-safe. ResizeObserver is only created on the client.
Examples
Responsive Layout
function AdaptiveLayout() {
const [ref, { width }] = useMeasure()
return (
<div ref={ref}>
{width > 768 ? (
<DesktopLayout />
) : width > 480 ? (
<TabletLayout />
) : (
<MobileLayout />
)}
</div>
)
}
Aspect Ratio Container
function VideoContainer() {
const [ref, { width }] = useMeasure()
const height = width * (9 / 16) // 16:9 aspect ratio
return (
<div ref={ref} style={{ height }}>
<video style={{ width: '100%', height: '100%' }} />
</div>
)
}
Canvas Sizing
function ResponsiveCanvas() {
const canvasRef = useRef<HTMLCanvasElement>(null)
const [containerRef, { width, height }] = useMeasure()
useEffect(() => {
if (canvasRef.current) {
const dpr = window.devicePixelRatio || 1
canvasRef.current.width = width * dpr
canvasRef.current.height = height * dpr
const ctx = canvasRef.current.getContext('2d')
ctx?.scale(dpr, dpr)
// Draw...
}
}, [width, height])
return (
<div ref={containerRef} className="w-full h-full">
<canvas
ref={canvasRef}
style={{ width, height }}
/>
</div>
)
}
Text Truncation
function AutoTruncate({ text }: { text: string }) {
const [ref, { width }] = useMeasure()
const charsPerPixel = 0.1 // Approximate
const maxChars = Math.floor(width * charsPerPixel)
return (
<div ref={ref}>
{text.length > maxChars
? `${text.slice(0, maxChars)}...`
: text}
</div>
)
}
Chart Sizing
function ResponsiveChart({ data }: { data: number[] }) {
const [ref, { width, height }] = useMeasure()
return (
<div ref={ref} className="w-full h-64">
{width > 0 && height > 0 && (
<svg width={width} height={height}>
{/* Render chart with actual dimensions */}
</svg>
)}
</div>
)
}
Performance
The hook uses ResizeObserver which is optimized by the browser:
- Updates are batched with other layout operations
- Observations are passive and don't block the main thread
- Memory is properly cleaned up when elements are removed
TypeScript
The hook accepts a generic type parameter for the element type:
const [ref, bounds] = useMeasure<HTMLDivElement>()
<div ref={ref}>...</div>
This provides proper typing for the ref callback.