react-dimensions, react-measure, react-resize-detector, and react-visibility-sensor are React libraries designed to detect changes in element dimensions or visibility within the browser viewport. They enable developers to build responsive components that adapt to container size changes or trigger actions when elements enter or leave the visible area. While all address layout-related reactivity, they differ significantly in implementation approach, underlying browser APIs, maintenance status, and specific use cases—ranging from simple dimension reporting to viewport visibility tracking.
When building responsive, dynamic UIs in React, you often need to know when an element changes size or becomes visible in the viewport. These four packages — react-dimensions, react-measure, react-resize-detector, and react-visibility-sensor — each tackle parts of this problem, but with different approaches, trade-offs, and current maintenance statuses. Let’s break them down for real-world use.
Before comparing features, it’s critical to address project health:
react-dimensions: Deprecated. The npm page states: "This package is no longer maintained. Please consider using react-resize-detector instead." Do not use in new projects.react-measure: Deprecated. The GitHub repo archive notice says: "This library is no longer maintained. Please use react-resize-observer or similar alternatives." Avoid in new work.react-resize-detector: Actively maintained. Regular updates, supports modern ResizeObserver API with fallbacks.react-visibility-sensor: Not officially deprecated, but last npm publish was in 2020. The GitHub repo shows low recent activity. Use with caution; consider Intersection Observer-based alternatives like @reach/observe-rect or native solutions.💡 Bottom line: For new projects,
react-resize-detectoris the only clearly recommended choice among these four for resize detection. For visibility, evaluate if a lightweight custom hook usingIntersectionObservermight be better.
react-dimensions (Deprecated)Used a higher-order component (HOC) that injected containerWidth and containerHeight as props. Relied on polling or event listeners (not ResizeObserver).
// ❌ DO NOT USE — deprecated
import Dimensions from 'react-dimensions';
const MyComponent = ({ containerWidth, containerHeight }) => (
<div>Size: {containerWidth} x {containerHeight}</div>
);
export default Dimensions()(MyComponent);
react-measure (Deprecated)Provided a render-prop component (<Measure>) that reported client rect dimensions via callback. Used DOM mutation observers and scroll/resize events.
// ❌ DO NOT USE — deprecated
import Measure from 'react-measure';
const MyComponent = () => (
<Measure bounds onResize={({ bounds }) => console.log(bounds)}>
{({ measureRef }) => <div ref={measureRef}>Content</div>}
</Measure>
);
react-resize-detectorOffers both component and hook APIs. Uses ResizeObserver under the hood (with polyfill support). Highly configurable.
// ✅ Recommended for resize detection
import { useResizeDetector } from 'react-resize-detector';
const MyComponent = () => {
const { width, height, ref } = useResizeDetector();
return <div ref={ref}>Size: {width} x {height}</div>;
};
// Or as a component
import ResizeDetector from 'react-resize-detector';
<ResizeDetector handleWidth handleHeight onResize={(width, height) => {}}>
<div>Content</div>
</ResizeDetector>
react-visibility-sensorFocused only on visibility, not dimensions. Used getBoundingClientRect() and scroll/resize listeners to determine if an element is in the viewport.
// ⚠️ Use with caution — outdated
import VisibilitySensor from 'react-visibility-sensor';
const MyComponent = () => (
<VisibilitySensor onChange={(isVisible) => console.log(isVisible)}>
<div>Watch me appear!</div>
</VisibilitySensor>
);
| Feature | react-dimensions | react-measure | react-resize-detector | react-visibility-sensor |
|---|---|---|---|---|
| Resize detection | ✅ (deprecated) | ✅ (deprecated) | ✅ (modern) | ❌ |
| Visibility detection | ❌ | ❌ | ❌ | ✅ (outdated method) |
| Uses ResizeObserver | ❌ | ❌ | ✅ | ❌ |
| Hook API | ❌ | ❌ | ✅ | ❌ |
| Render-prop / HOC | HOC | Render-prop | Component + Hook | Render-prop |
| Active maintenance | ❌ | ❌ | ✅ | ⚠️ (inactive) |
You’re using D3 or Chart.js and need to redraw when the parent div resizes.
react-resize-detectorimport { useResizeDetector } from 'react-resize-detector';
import { useEffect } from 'react';
const ResponsiveChart = () => {
const { width, height, ref } = useResizeDetector();
useEffect(() => {
if (width && height) {
drawChart(width, height); // Your chart logic
}
}, [width, height]);
return <div ref={ref} style={{ width: '100%', height: 400 }} />;
};
You want to load images only when they become visible.
react-visibility-sensor works but is outdatedIntersectionObserver with a custom hook or libraries like react-intersection-observer.// Using react-visibility-sensor (not ideal)
<VisibilitySensor partialVisibility offset={{ bottom: 200 }}>
<img src="image.jpg" alt="lazy" />
</VisibilitySensor>
// Modern alternative (recommended)
import { useInView } from 'react-intersection-observer';
const LazyImage = () => {
const { ref, inView } = useInView({ triggerOnce: true, rootMargin: '200px' });
return <img ref={ref} src={inView ? 'image.jpg' : placeholder} />;
};
You need to know if text overflows its container to show “Read more”.
react-resize-detectorreact-visibility-sensor doesn’t help here.const TruncatedText = ({ text }) => {
const { width, ref: containerRef } = useResizeDetector();
const { width: textWidth, ref: textRef } = useResizeDetector();
const isOverflowing = textWidth > width;
return (
<div ref={containerRef} style={{ width: '100%', overflow: 'hidden' }}>
<span ref={textRef}>{text}</span>
{isOverflowing && <button>Show more</button>}
</div>
);
};
react-dimensions and react-measure used legacy techniques (polling, scroll/resize event listeners) that could cause layout thrashing or miss rapid changes.react-resize-detector leverages ResizeObserver, which is asynchronous, efficient, and fires only when actual layout changes occur.react-visibility-sensor uses getBoundingClientRect() on every scroll/resize, which can hurt performance on complex pages. Modern IntersectionObserver is far more efficient.If you’re maintaining a codebase using deprecated packages:
From react-dimensions → react-resize-detector:
Replace HOC with useResizeDetector hook.
From react-measure → react-resize-detector:
Replace <Measure> render prop with hook or component API.
From react-visibility-sensor → modern alternative:
Consider react-intersection-observer or a minimal custom hook:
// Simple custom visibility hook
function useVisibility(ref, options = {}) {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
setIsVisible(entry.isIntersecting);
}, options);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, [ref, options]);
return isVisible;
}
react-resize-detector. It’s the only actively maintained, modern solution in this group.react-visibility-sensor in new projects. Prefer react-intersection-observer or a lightweight custom hook using the native IntersectionObserver API.react-dimensions or react-measure — they are officially deprecated and lack modern performance optimizations.These tools solve real problems, but the JavaScript ecosystem has evolved. Leverage browser APIs like ResizeObserver and IntersectionObserver through well-maintained wrappers — your app’s performance and maintainability will thank you.
Choose react-resize-detector when you need reliable, performant detection of element dimension changes in React. It offers both hook and component APIs, uses the modern ResizeObserver API with polyfill support, and is actively maintained. Ideal for responsive charts, dynamic layouts, or any component that must react to container resizing.
Avoid react-measure for new development as it is deprecated and archived on GitHub. The library relied on older DOM measurement techniques and lacks support for modern ResizeObserver. Migrate existing usage to react-resize-detector or similar maintained alternatives.
Consider react-visibility-sensor only for simple visibility detection in low-complexity scenarios if you cannot adopt newer alternatives, but be aware it is effectively unmaintained (last update in 2020). For new projects, prefer libraries like react-intersection-observer or a custom hook using the native IntersectionObserver API for better performance and reliability.
Do not use react-dimensions in new projects — it is officially deprecated according to its npm page, which recommends migrating to react-resize-detector. If you encounter it in legacy code, plan a replacement using modern ResizeObserver-based solutions.
Modern browsers now have native support for detecting element size changes through ResizeObservers. This library utilizes ResizeObservers to facilitate managing element size changes in React applications.
🐥 Tiny ~2kb
🐼 Written in TypeScript
🐠 Used by 170k repositories
🦄 Produces 100 million downloads annually
No window.resize listeners! No timeouts!
Consider CSS Container Queries first! They now work in all major browsers and might solve your use case with pure CSS.
<div class="post">
<div class="card">
<h2>Card title</h2>
<p>Card content</p>
</div>
</div>
.post {
container-type: inline-size;
}
/* Default heading styles for the card title */
.card h2 {
font-size: 1em;
}
/* If the container is larger than 700px */
@container (min-width: 700px) {
.card h2 {
font-size: 2em;
}
}
Use this library when you need:
npm install react-resize-detector
# OR
yarn add react-resize-detector
# OR
pnpm add react-resize-detector
import { useResizeDetector } from 'react-resize-detector';
const CustomComponent = () => {
const { width, height, ref } = useResizeDetector<HTMLDivElement>();
return <div ref={ref}>{`${width}x${height}`}</div>;
};
import { useCallback } from 'react';
import { useResizeDetector, OnResizeCallback } from 'react-resize-detector';
const CustomComponent = () => {
const onResize: OnResizeCallback = useCallback((payload) => {
if (payload.width !== null && payload.height !== null) {
console.log('Dimensions:', payload.width, payload.height);
} else {
console.log('Element unmounted');
}
}, []);
const { width, height, ref } = useResizeDetector<HTMLDivElement>({
onResize,
});
return <div ref={ref}>{`${width}x${height}`}</div>;
};
It's not advised to use this approach, as dynamically mounting and unmounting the observed element could lead to unexpected behavior.
import { useRef } from 'react';
import { useResizeDetector } from 'react-resize-detector';
const CustomComponent = () => {
const targetRef = useRef<HTMLDivElement>(null);
const { width, height } = useResizeDetector({ targetRef });
return <div ref={targetRef}>{`${width}x${height}`}</div>;
};
useResizeDetector<T extends HTMLElement = HTMLElement>(
props?: useResizeDetectorProps<T>
): UseResizeDetectorReturn<T>
| Prop | Type | Description | Default |
|---|---|---|---|
onResize | (payload: ResizePayload) => void | Callback invoked with resize information | undefined |
handleWidth | boolean | Trigger updates on width changes | true |
handleHeight | boolean | Trigger updates on height changes | true |
skipOnMount | boolean | Skip the first resize event when component mounts | false |
disableRerender | boolean | Disable re-renders triggered by the hook. Only the onResize callback will be called | false |
refreshMode | 'throttle' | 'debounce' | Rate limiting strategy. See es-toolkit docs | undefined |
refreshRate | number | Delay in milliseconds for rate limiting | 1000 |
refreshOptions | { leading?: boolean; trailing?: boolean } | Additional options for throttle/debounce | undefined |
observerOptions | ResizeObserverOptions | Options passed to resizeObserver.observe | undefined |
targetRef | MutableRefObject<T | null> | External ref to observe (use with caution) | undefined |
import { useResizeDetector } from 'react-resize-detector';
const ResponsiveCard = () => {
const { width, ref } = useResizeDetector();
const cardStyle = {
padding: width > 600 ? '2rem' : '1rem',
fontSize: width > 400 ? '1.2em' : '1em',
flexDirection: width > 500 ? 'row' : 'column',
};
return (
<div ref={ref} style={cardStyle}>
<h2>Responsive Card</h2>
<p>Width: {width}px</p>
</div>
);
};
import { useResizeDetector } from 'react-resize-detector';
import { useEffect, useRef } from 'react';
const Chart = () => {
const chartRef = useRef(null);
const { width, height, ref } = useResizeDetector({
refreshMode: 'debounce',
refreshRate: 100,
});
useEffect(() => {
if (width && height && chartRef.current) {
// Redraw chart with new dimensions
redrawChart(chartRef.current, width, height);
}
}, [width, height]);
return <canvas ref={ref} />;
};
import { useResizeDetector } from 'react-resize-detector';
const OptimizedComponent = () => {
const { width, height, ref } = useResizeDetector({
// Only track width changes
handleHeight: false,
// Debounce rapid changes
refreshMode: 'debounce',
refreshRate: 150,
// Skip initial mount calculation
skipOnMount: true,
// Use border-box for more accurate measurements
observerOptions: { box: 'border-box' },
});
return <div ref={ref}>Optimized: {width}px wide</div>;
};
import { useResizeDetector } from 'react-resize-detector';
const NonRerenderingComponent = () => {
const { ref } = useResizeDetector({
// Disable re-renders triggered by the hook
disableRerender: true,
// Handle resize events through callback only
onResize: ({ width, height }) => {
// Update external state or perform side effects
// without causing component re-renders
console.log('Resized to:', width, height);
},
});
return <div ref={ref}>This component won't re-render on resize</div>;
};
For older browsers, consider using a ResizeObserver polyfill.
const { ResizeObserver } = window;
beforeEach(() => {
delete window.ResizeObserver;
// Mock ResizeObserver for tests
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
handleWidth/handleHeight: false if you only need one dimensionskipOnMount: true if you don't need initial measurementsdebounce or throttle for expensive resize handlersobserverOptions.box for consistent measurementsMIT
Show us some love and STAR ⭐ the project if you find it useful