Skip to content

Latest commit

 

History

History
118 lines (88 loc) · 4.05 KB

File metadata and controls

118 lines (88 loc) · 4.05 KB
title Shapes
status published
author steveruizok
date 3/22/2023
order 2
keywords
custom
shapes
shapeutils
utils

In tldraw, a shape is something that can exist on the page, like an arrow, an image, or some text. This article provides an overview of shapes and how to create custom ones.

Shape basics

Shapes are JSON records stored in the editor's store. Each shape has base properties (position, rotation, opacity) plus a props object for shape-specific data. See Shapes for the full shape system architecture.

The Tldraw component includes default shapes like geo, text, arrow, and draw. The only core shape (always present) is the group.

ShapeUtil

Each shape type has a ShapeUtil class that defines its behavior: how it renders, its geometry for hit testing, and how it responds to interactions. See Shapes for details on ShapeUtil methods, lifecycle hooks, and configuration.

Custom shapes

You can create your own shapes by defining a shape type and a ShapeUtil class.

For a working example, see our custom shapes example.

Defining the shape type

Register your shape's props using TypeScript module augmentation:

const CARD_TYPE = 'card'

declare module 'tldraw' {
	export interface TLGlobalShapePropsMap {
		[CARD_TYPE]: { w: number; h: number }
	}
}

type CardShape = TLShape<typeof CARD_TYPE>

Creating a ShapeUtil

Implement the required methods: getDefaultProps, getGeometry, component, and indicator:

import { HTMLContainer, Rectangle2d, ShapeUtil } from 'tldraw'

class CardShapeUtil extends ShapeUtil<CardShape> {
	static override type = CARD_TYPE

	getDefaultProps(): CardShape['props'] {
		return { w: 100, h: 100 }
	}

	getGeometry(shape: CardShape) {
		return new Rectangle2d({
			width: shape.props.w,
			height: shape.props.h,
			isFilled: true,
		})
	}

	component(shape: CardShape) {
		return <HTMLContainer>Hello</HTMLContainer>
	}

	indicator(shape: CardShape) {
		return <rect width={shape.props.w} height={shape.props.h} />
	}
}

See Geometry for available geometry classes.

Registering your shape

Pass your ShapeUtil to the Tldraw component:

export default function () {
	return (
		<div style={{ position: 'fixed', inset: 0 }}>
			<Tldraw
				shapeUtils={[CardShapeUtil]}
				onMount={(editor) => {
					editor.createShape({ type: 'card' })
				}}
			/>
		</div>
	)
}

Extending shapes

Related topics

Topic Description
Shapes Full shape system architecture, ShapeUtil methods, lifecycle hooks
Default shapes Built-in shape types and their properties
Geometry Geometry classes for hit testing and bounds
Bindings Connecting shapes together (like arrows)
Rich text Adding text labels to shapes
Shape clipping Clipping children within shape boundaries
Snapping Shape snapping behavior
Persistence Shape migrations and data persistence
Groups Grouping shapes together