Skip to main content
Version: 4.3

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

ParameterTypeDefault valueDescription
nodeRefRefObject<HTMLElement | SVGElement | null>undefinedRef to the HTML or SVG node to measure. It must be mounted in the DOM while the hook runs.
optionsMeasureElementOptionsEMPTY_OBJECTOptional 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 renderElement callback (or a component rendered from one); it reads the current cell from context and throws otherwise.
  • When several useMeasureElement calls 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 live width/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>
</>
);
}

Stay in the know

Be where thousands of diagramming enthusiasts meet

Star us on GitHub