useMeasureElement()
function useMeasureElement(nodeRef, options?): Required<ElementSize>;
Measures a rendered DOM node and keeps the graph element's size in sync with
it. Point nodeRef at the HTML or SVG node that defines the element's size;
whenever that node resizes, the matching graph element is resized to match
(optionally adjusted by a transform, see MeasureElementOptions), and
the element's current width/height are returned for your own layout math.
Reach for it when an element's size is driven by its rendered content rather than fixed up front, e.g. text that wraps or a list that grows.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
nodeRef | RefObject<HTMLElement | SVGElement | null> | undefined | Ref to the HTML or SVG node to measure. It must be mounted in the DOM while the hook runs. |
options | MeasureElementOptions | EMPTY_OBJECT | Optional MeasureElementOptions; the main option is a transform that adjusts the measured size before it is applied. |
Returns
Required<ElementSize>
The graph element's current width and height (always defined).
Remarks
- Call this inside a
renderElementcallback (or a component rendered from one); it reads the current cell from context and throws otherwise. - When several
useMeasureElementcalls target the same element, the most recently mounted one wins. When it unmounts, the previous one takes over again. - Do not also read the size back with the selectElementSize selector
(or
useCell((cell) => cell.size)) in the same component. This hook already syncs the size and returns the livewidth/height; reading it again only adds a redundant subscription and an extra render.
Throws
If used outside a renderElement context, or if the current cell is a
link rather than an element.
Examples
Basic usage
import { useMeasureElement } from '@joint/react';
import { useRef } from 'react';
// The element grows to fit its text label.
function LabelElement() {
const textRef = useRef<SVGTextElement>(null);
const { width, height } = useMeasureElement(textRef);
return (
<>
<rect width={width} height={height} fill="#333" />
<text ref={textRef} x={4} y={16} fill="#fff">Hello world</text>
</>
);
}
Use the returned size
import { useMeasureElement } from '@joint/react';
import { useRef } from 'react';
const iconURL = 'https://example.com/icon.svg';
// Size follows the HTML content; use the returned size to place an icon inside.
function Card() {
const contentRef = useRef<HTMLDivElement>(null);
const { width, height } = useMeasureElement(contentRef);
const iconSize = 16;
return (
<>
<rect width={width} height={height} fill="#333" />
<image href={iconURL} x={width - iconSize} y={0} width={iconSize} height={iconSize} />
<foreignObject width={width} height={height}>
<div ref={contentRef} style={{ padding: 8, color: '#fff' }}>Card content</div>
</foreignObject>
</>
);
}
Adjust size with a transform
import { useMeasureElement, type TransformElementLayout } from '@joint/react';
import { useRef, useCallback } from 'react';
function ListElement() {
const divRef = useRef<HTMLDivElement>(null);
const padding = 10;
const headerHeight = 50;
const transform: TransformElementLayout = useCallback(
({ width: measuredWidth, height: measuredHeight }) => {
return {
width: padding + measuredWidth + padding,
height: headerHeight + measuredHeight + padding,
};
},
[]
);
const { width, height } = useMeasureElement(divRef, { transform });
return (
<>
<rect width={width} height={height} fill="#121826" />
<foreignObject x={padding} y={headerHeight} width={width - 2 * padding} height={height - headerHeight - padding}>
<div ref={divRef}>Content</div>
</foreignObject>
</>
);
}