Skip to main content
Version: 4.3

Using Built-in Shapes

@joint/react is optimized for React-rendered nodes. If you want native JointJS shapes instead, you can use them directly by setting type on your cell record. Use this path when you want native JointJS model and view behavior, or when you want to reuse the built-in shape catalog instead of building the node with renderElement.

Basic usage​

Core JointJS standard shapes already work with the default GraphProvider namespace. The simplest pattern is just setting type and passing native attrs through the record.

The important part is the type field. Once it points at a native JointJS shape or link type, @joint/react creates that native cell instead of the default React-rendered one.

What changes when you use built-in shapes​

The main shift is that the node is no longer rendered by React.

  • the basic example does not pass renderElement
  • styling and behavior move into native JointJS attrs and native shape APIs
  • selectors come from the native shape definition, such as body, label, line, outline, header, or bodyText

This is why the example above writes directly to attrs.body, attrs.label, attrs.line, and similar selectors instead of returning JSX.

The data field still gets stored on the cell and is readable via cell.get('data'), but the basic example does not consume it. Use data for application-level metadata you plan to read from graph events or code. To layer React content on top of a native shape, see Rendering React inside native shapes.

Mixing native and React-rendered shapes​

Native shapes and React-rendered elements can coexist in the same graph. Records with a native type use the built-in path, while records typed 'element' still go through renderElement:

const initialCells = [
{
id: 'native',
type: 'standard.Rectangle',
position: { x: 40, y: 40 },
size: { width: 120, height: 56 },
attrs: { body: { fill: '#ffffff' }, label: { text: 'Native' } },
},
{
id: 'react',
type: 'element',
position: { x: 220, y: 40 },
size: { width: 120, height: 56 },
data: { label: 'React-rendered' },
},
];

This is useful when part of the diagram benefits from the native shape catalog while the rest needs custom React components.

When to choose this path​

Choose built-in shapes when:

  • you want the standard JointJS shape catalog
  • you want a native JointJS shape or link type such as standard.HeaderedRectangle or standard.DoubleLink
  • you want to work directly with native attrs selectors and shape-specific APIs

Stay with Elements and Links when the node or link should be rendered and composed with React.

Custom and JointJS+ shapes​

The same type pattern works with any shape constructor, your own custom classes and JointJS+ shapes included. The difference is that the graph must know those constructors, so you pass them through cellNamespace.

Your own custom shapes (see Creating a shape from scratch for how to define them and Cell namespaces for the namespace mechanics):

import { GraphProvider, Paper } from '@joint/react';
import { TaskShape } from './task-shape';

<GraphProvider cellNamespace={{ TaskShape }} initialCells={initialCells}>
<Paper />
</GraphProvider>

JointJS+ shapes from @joint/plus. @joint/react-plus ships as part of the JointJS+ distribution; install the version that matches your JointJS+ release, alongside @joint/plus:

import { GraphProvider, Paper } from '@joint/react-plus';
import { shapes } from '@joint/plus';

<GraphProvider cellNamespace={shapes} initialCells={initialCells}>
<Paper />
</GraphProvider>

For core standard.* shapes, the default GraphProvider namespace is already enough. The extra namespace step only matters when the shape constructors come from outside the core catalog.

Constraints and notes​

  • Built-in shapes are a native JointJS path, not the default React-first path
  • type and attrs are the important fields to control
  • Native link types work the same way as native element types
  • If you need lower-level model and graph work beyond declarative records, continue to Querying the Graph