Skip to main content
Version: 4.3

Measuring Elements

HTMLHost already handles normal HTML auto-sizing for you. useMeasureElement() is the lower-level hook for the cases where rendered content should determine the element's final size, most often when you are returning raw SVG from renderElement.

This chapter is the advanced continuation of Elements.

Basic usage​

The most common pattern is:

  1. Attach a ref to the SVG node you want to measure
  2. Call useMeasureElement(ref, { transform })
  3. Use the returned width and height to draw the rest of the element

Each badge below has a different label. The measured <text> node drives the pill width, so none of the elements have a fixed size.

What the hook returns​

useMeasureElement() returns the applied element size:

const { width, height } = useMeasureElement(textRef, { transform });

Those values are the applied element size after transform runs, not just the raw measured size of the DOM or SVG node.

Using transform​

transform is the main option to know. It lets you convert the measured content size into the final element size stored in graph state.

const transform: TransformElementLayout = ({ width, height }) => ({
width: width + 24,
height: height + 16,
});

That is the usual pattern for adding padding around measured text or another SVG node.

The callback receives more than the raw measured size. Alongside width and height, it also gets the current element layout and metadata such as x, y, angle, model (the dia.Element instance), and id.

You can also return x and y when the measured content should shift the element origin, but most custom elements only adjust width and height.

Anchor point: autoSizeOrigin​

By default the element's top-left corner stays fixed as its measured size changes: the element grows down and to the right. Set autoSizeOrigin="center" on <GraphProvider> to keep the geometric center fixed instead, so the element grows symmetrically.

<GraphProvider initialCells={initialCells} autoSizeOrigin="center">
<Paper renderElement={Badge} />
</GraphProvider>

This only affects measurement-driven writes. Manual cell.resize(), the interactive resize tool, and direct cell.set('size', ...) calls are unaffected.

Laying out other SVG content​

The returned size is not just output. It also becomes the layout input for sibling SVG nodes.

This example places a status indicator circle before the label. The measured text width determines the chip width, and the returned height keeps the icon and text vertically aligned.

Reacting after measurement​

When measured nodes share the canvas, you sometimes need to wait for layout to settle before running follow-up logic: fitting the paper to content, focusing a node, or computing a derived layout. useOnElementsMeasured() is the hook for that.

It fires once the paper has measured its elements (and again when sizes change later). The callback receives { isInitial, paper, graph }. isInitial distinguishes the first measurement from subsequent ones, and paper/graph are the resolved instances at firing time.

The most common setup reads the resolved paper straight from the callback:

import { GraphProvider, Paper, useOnElementsMeasured } from '@joint/react';

function Canvas() {
useOnElementsMeasured(({ isInitial, paper }) => {
if (isInitial) {
paper.transformToFitContent({ padding: 20 });
}
});

return <Paper />;
}

export default function App() {
return (
<GraphProvider initialCells={initialCells}>
<Canvas />
</GraphProvider>
);
}

Called with no target, as in useOnElementsMeasured(callback), it resolves the single default paper automatically, so you can call it anywhere inside <GraphProvider>.

Targeting a specific paper

useOnElementsMeasured() resolves the single default paper automatically. Pass a paper id or ref as the first argument, as in useOnElementsMeasured(paperTarget, callback), to target a specific paper when your app renders more than one.

The callback fires on the initial measurement and again on every later re-measurement. Gate on isInitial to act only on the first, or use the payload each time to react to every change.

Constraints and notes​

  • Use useMeasureElement() inside renderElement or a component rendered from it
  • It works with elements, not links
  • The hook returns only width and height. For x, y, or angle, use useCell(selectElement…) selectors
  • For standard HTML nodes, start with HTMLHost in Elements
  • If the element already has a fixed size, explicit size plus useCell(selectElementSize) is usually simpler. Do not also call useCell(selectElementSize) in the same component when measuring; useMeasureElement already returns the live size
  • Use useOnElementsMeasured() when you need to run code after measurement, not during it