Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungWhat is Programming And How i can Enjoy it?(24.09.2026 um 11:54 Uhr)
Sichere ProgrammierungYou Don't Need Adobe Commerce Cloud to Survive Black Friday(24.09.2026 um 11:55 Uhr)
Malware / Trojaner / VirenBeyond Lazarus: Organization of DPRK cyber capabilities(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenBeyond Lazarus: Organization of DPRK Cyber Capabilities(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenThe fake worker threat and the rise of human infiltration(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenPolinRider Spreads Through Compromised GitHub Accounts and Packagist(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenWeaselBiscuit Strips BeaverTail and OtterCookie Down to Essentials(24.09.2026 um 11:59 Uhr)
Sichere ProgrammierungWhat is Programming And How i can Enjoy it?(24.09.2026 um 11:54 Uhr)
Sichere ProgrammierungYou Don't Need Adobe Commerce Cloud to Survive Black Friday(24.09.2026 um 11:55 Uhr)
Malware / Trojaner / VirenBeyond Lazarus: Organization of DPRK cyber capabilities(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenBeyond Lazarus: Organization of DPRK Cyber Capabilities(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenThe fake worker threat and the rise of human infiltration(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenPolinRider Spreads Through Compromised GitHub Accounts and Packagist(24.09.2026 um 11:59 Uhr)
Malware / Trojaner / VirenWeaselBiscuit Strips BeaverTail and OtterCookie Down to Essentials(24.09.2026 um 11:59 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

React useMeasure Hook: Measure DOM Elements with ResizeObserver (2026)

Sooner or later every React app needs to know how big an element is. A chart needs its container's pixel width before it can draw. A virtualized list needs row heights. An auto-growing textarea, a truncation detector, a component that…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Sooner or later every React app needs to know how big an element is. A chart needs its container's pixel width before it can draw. A virtualized list needs row heights. An auto-growing textarea, a truncation detector, a component that switches layout when it — not the viewport — gets narrow: all of them need live element dimensions, and React doesn't provide them. So you reach for getBoundingClientRect() in an effect, discover it only runs once, add a resize listener on window, and then notice the element also resizes when a sibling collapses, a font loads, or content changes — none of which fire a window resize event.



The correct primitive is ResizeObserver, and useMeasure from @reactuses/core is that primitive wrapped into one line: pass a ref, get back a live rect. No observer construction, no disconnect bookkeeping, no stale-closure traps. This post walks the API, the contentRect gotcha that trips almost everyone, how the hook works inside, how it compares to its sibling hooks (useElementSize, useElementBounding, useResizeObserver), and migration from react-use-measure. TypeScript-first.






The Simplest Case: A Live-Sized Container






import { useRef } from 'react';
import { useMeasure } from '@reactuses/core';

function Chart() {
const ref = useRef<HTMLDivElement>(null);
const [rect] = useMeasure(ref);

return (
<div ref={ref} style={{ width: '100%', height: '400px' }}>
<svg width={rect.width} height={rect.height}>
{/* draw with real pixel dimensions */}
</svg>
</div>
);
}






That's the whole pattern: a ref on the element, useMeasure(ref), and a rect that re-renders the component whenever the element's content box changes size — window resizes, flexbox reflows, sidebar toggles, font swaps, anything. You never touch ResizeObserver directly and there's no cleanup to remember; the observer disconnects automatically on unmount.






The Full API






const [rect, stop] = useMeasure(target, options?);






target accepts the same flexible shapes as every element hook in @reactuses/core:




useMeasure(ref);                          // a React ref object
useMeasure(document.querySelector('#el')); // a raw Element
useMeasure(() => document.body); // a function returning an element






options is a standard ResizeObserverOptions object — { box: 'content-box' | 'border-box' | 'device-pixel-content-box' } — controlling which box triggers observations.



rect is a UseMeasureRect:




type UseMeasureRect = {
x: number;
y: number;
width: number;
height: number;
top: number;
left: number;
bottom: number;
right: number;
};






Before the first observation fires (including during SSR), every field is 0.



stop is a function that disconnects the observer. Call it when you've measured what you needed and don't want further re-renders — say, after capturing an initial layout for an animation:




const [rect, stop] = useMeasure(ref);

useEffect(() => {
if (rect.width > 0) {
startEnterAnimation(rect);
stop(); // one measurement was enough
}
}, [rect, stop]);









The contentRect Gotcha: top/left Are Not Viewport Coordinates



This is the number-one confusion with every ResizeObserver-based measure hook, so let's kill it early. The rect comes from entry.contentRect, and contentRect is relative to the element's own box, not the viewport:





  • width / height — the content box size: excludes padding, border, and scrollbars.


  • top / left (and x / y) — the offset of the content box from the element's border box. In practice: your padding-top and padding-left, not the element's position on the page.



So for an element with padding: 16px sitting 300px down the page, useMeasure reports top: 16, not top: 300. If what you actually want is where the element is on screen — for positioning a tooltip, a dropdown, a spotlight overlay — you want getBoundingClientRect() semantics, and that's a different hook: useElementBounding, which returns viewport-relative coordinates and also updates on scroll.



Rule of thumb: useMeasure answers "how big is it?"; useElementBounding answers "where is it?"






How It Works Inside



useMeasure is a thin layer over the library's useResizeObserver hook:




import { useState } from 'react';
import { useResizeObserver } from '../useResizeObserver';

export const useMeasure = (target, options = defaultOptions) => {
const [rect, setRect] = useState(defaultState); // all zeros

const stop = useResizeObserver(
target,
entries => {
if (entries[0]) {
const { x, y, width, height, top, left, bottom, right }
= entries[0].contentRect;
setRect({ x, y, width, height, top, left, bottom, right });
}
},
options,
);

return [rect, stop] as const;
};






The interesting machinery lives in useResizeObserver:




export const useResizeObserver = (target, callback, options) => {
const savedCallback = useLatest(callback);
const observerRef = useRef<ResizeObserver>();
const { key: targetKey, ref: targetRef } = useStableTarget(target);

const stop = useCallback(() => {
observerRef.current?.disconnect();
}, []);

useDeepCompareEffect(() => {
const element = getTargetElement(targetRef.current);
if (!element) return;
observerRef.current = new ResizeObserver(savedCallback.current);
observerRef.current.observe(element, options);
return stop;
}, [targetKey, options]);

return stop;
};






Three details worth noticing:




  1. useLatest wraps the callback — you can pass an inline arrow function without tearing down and recreating the observer on every render. The observer is constructed once; the ref always points at the latest callback.


  2. useDeepCompareEffect guards the options objectuseMeasure(ref, { box: 'border-box' }) passes a fresh object literal every render. A plain useEffect with [options] would disconnect and reconnect the observer each time. Deep comparison means the observer only rebuilds when the options values actually change.


  3. The observer is created inside an effect — effects don't run on the server, so new ResizeObserver(...) never executes during SSR. The hook is SSR-safe by construction: the server renders with the all-zeros rect, the client hydrates identically, and the first observation fires after mount.




That third point also explains the initial { width: 0, height: 0 } render. Guard against it when zero would break your math:




const [rect] = useMeasure(ref);

return (
<div ref={ref}>
{rect.width > 0 && <Chart width={rect.width} height={rect.height} />}
</div>
);









useMeasure vs useElementSize vs useElementBounding vs useResizeObserver



@reactuses/core ships four hooks in this space. They're layered, not redundant:

























































useMeasure useElementSize useElementBounding useResizeObserver
Returns
[rect, stop] — full 8-field rect
[width, height]
{ x, y, top, left, ... } viewport-relative

stop (you get raw entries in a callback)
Source contentRect
contentBoxSize / borderBoxSize
getBoundingClientRect() Raw ResizeObserverEntry[]
Coordinates Element-relative (padding offsets) — (size only) Viewport-relative Whatever you read from entries
Updates on scroll No No
Yes (window scroll + resize listeners)
No
Box option Observation trigger only Measured value follows box Observation trigger only
Best for Size + a stop switch Just width/height, minimal re-renders Tooltips, popovers, overlays — positioning Custom logic; multiple elements; no state updates


Two distinctions deserve a sentence each:





  • useElementSize respects the box option in the measured value. With { box: 'border-box' } it reports borderBoxSize — padding and border included — which is what you usually mean by "how big is this element". useMeasure always reports the content box regardless of which box triggers observation, because contentRect is all ResizeObserver entries expose rect-wise.


  • useElementBounding is the only one that tracks position on scroll. It observes with ResizeObserver and listens to window scroll / resize (passive), recomputing getBoundingClientRect() on each. Heavier, but correct for anything anchored to screen position.



If you just need the viewport size, skip element observation entirely — that's useWindowSize.






Patterns






Container-Query-Style Responsive Component



Media queries respond to the viewport; components live in containers. A card in a wide main column and the same card in a narrow sidebar should lay out differently even on the same screen:




function ProfileCard() {
const ref = useRef<HTMLDivElement>(null);
const [rect] = useMeasure(ref);
const compact = rect.width > 0 && rect.width < 320;

return (
<div ref={ref} className={compact ? 'card card--stacked' : 'card card--row'}>
<Avatar />
<Bio truncated={compact} />
</div>
);
}






The component adapts to the space it's given, wherever it's mounted. (CSS container queries cover the styling half of this; useMeasure covers the half where JavaScript needs the number — chart scales, virtualization math, conditional rendering.)






Canvas / SVG That Fills Its Parent



Canvas and SVG need explicit pixel dimensions. Bind them to the measured parent and redraw on change:




function Sparkline({ data }: { data: number[] }) {
const wrapRef = useRef<HTMLDivElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
const [rect] = useMeasure(wrapRef);

useEffect(() => {
const canvas = canvasRef.current;
if (!canvas || rect.width === 0) return;
canvas.width = rect.width * devicePixelRatio;
canvas.height = rect.height * devicePixelRatio;
drawSparkline(canvas, data);
}, [rect, data]);

return (
<div ref={wrapRef} className="sparkline-wrap">
<canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} />
</div>
);
}






Every layout change — panel resize, sidebar collapse, orientation flip — re-renders the canvas at the correct resolution. No window.resize listener, which would miss the panel-resize and sidebar cases entirely.






Auto-Height Animation (Measure, Then Animate)



CSS can't transition height: auto. Measure the content, animate to the number:




function Collapsible({ open, children }: Props) {
const innerRef = useRef<HTMLDivElement>(null);
const [rect] = useMeasure(innerRef);

return (
<div
style={{
height: open ? rect.height : 0,
overflow: 'hidden',
transition: 'height 200ms ease',
}}
>
<div ref={innerRef}>{children}</div>
</div>
);
}






Because the measurement is live, the panel stays correct even if its content changes while open — an image finishes loading, a nested section expands. A one-shot getBoundingClientRect() snapshot would go stale the moment content shifted.






Truncation Detection



Show a "read more" affordance only when text actually overflows:




function Excerpt({ text }: { text: string }) {
const ref = useRef<HTMLParagraphElement>(null);
const [rect] = useMeasure(ref);
const truncated =
ref.current != null && ref.current.scrollHeight > Math.ceil(rect.height);

return (
<>
<p ref={ref} className="clamp-3">{text}</p>
{truncated && <button>Read more</button>}
</>
);
}






rect.height is the visible (clamped) content height, scrollHeight the full content height; comparing them detects overflow — and keeps detecting it as the container resizes, which is exactly when truncation state flips.






Coming from react-use-measure



If you've used pmndrs' react-use-measure, the mental model transfers directly — with a few differences:




// react-use-measure — hook creates the ref for you
const [ref, bounds] = useMeasure();
<div ref={ref} />

// @reactuses/core — you own the ref (or pass an element/function)
const ref = useRef<HTMLDivElement>(null);
const [rect, stop] = useMeasure(ref);
<div ref={ref} />








  • Ref ownership: react-use-measure returns a callback ref; @reactuses/core accepts your ref, a raw element, or a getter function. Owning the ref means you can share it with other hooks (useClickOutside, useHover) on the same element without ref-merging utilities.


  • Coordinates: react-use-measure reports viewport-relative bounds (with an optional scroll option); @reactuses/core's useMeasure reports contentRect. For viewport-relative-plus-scroll behavior, use useElementBounding — that's the true equivalent.


  • Debounce: react-use-measure takes a debounce option. Here you compose instead: pipe the rect through useDebounce if you need to throttle downstream work.


  • Stop switch: only @reactuses/core gives you stop — a clean way to end observation after you've got what you came for.


  • One library, 100+ hooks: you're pulling from a full collection rather than adding a single-purpose dependency.






Takeaways





  • useMeasure gives you a live element rect with one line — ResizeObserver underneath, zero observer bookkeeping, automatic cleanup.


  • It measures the content box, element-relative. top/left are padding offsets, not page position. For viewport coordinates and scroll tracking, use useElementBounding; for border-box sizes, useElementSize with { box: 'border-box' }.


  • The first render is all zeros — on the server and before the first observation. Guard rect.width > 0 where zero breaks your math.


  • Inline callbacks and fresh options objects are safeuseLatest and useDeepCompareEffect inside prevent observer churn.


  • stop ends observation on demand — measure once for an animation, then stop paying for re-renders.


  • SSR-safe by construction — the observer is created in an effect, which never runs on the server.



Grab it from @reactuses/core and stop hand-rolling ResizeObserver wiring.

SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - React useMeasure Hook: Measure DOM Elements with ResizeObserver (2026)
id: 1a9a4072-1f59-4ba2-9009-27b84d77cfb4
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "React useMeasure Hook: Measure" ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich React useMeasure Hook: Measure DOM Eleme.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Zum Aktualisieren ziehen
ZERO-DAY Kritische Sicherheitsmeldung
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick