apps/docs/content/sdk-features/arrow-shape.mdx
The arrow shape draws a connector between two points on the canvas. Arrows can bind to other shapes, so they stay attached when those shapes move. Arrows route as curved arcs or right-angled elbows, take one of nine arrowhead styles at each end, and can carry a rich text label.
An arrow is a shape of type arrow. Its start and end props are points relative to the shape's position:
import { Tldraw, toRichText } from 'tldraw'
import 'tldraw/tldraw.css'
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw
onMount={(editor) => {
editor.createShape({
type: 'arrow',
x: 100,
y: 100,
props: {
start: { x: 0, y: 0 },
end: { x: 300, y: 100 },
richText: toRichText('connects to'),
},
})
}}
/>
</div>
)
}
The full set of props on TLArrowShape:
| Property | Type | Description |
|---|---|---|
kind | TLArrowShapeKind | Routing mode: arc (default) or elbow |
start | VecModel | Start terminal position, relative to the shape origin |
end | VecModel | End terminal position |
bend | number | Curvature for arc arrows (0 = straight) |
elbowMidPoint | number | Position (0–1) of the middle segment for elbow arrows |
color | TLDefaultColorStyle | Stroke color |
fill | TLDefaultFillStyle | Fill style for arrowheads |
dash | TLDefaultDashStyle | Stroke pattern |
size | TLDefaultSizeStyle | Stroke width preset |
arrowheadStart | TLArrowShapeArrowheadStyle | Arrowhead at the start (default none) |
arrowheadEnd | TLArrowShapeArrowheadStyle | Arrowhead at the end (default arrow) |
richText | TLRichText | Optional text label |
labelPosition | number | Label position along the arrow (0 = start, 1 = end) |
labelColor | TLDefaultColorStyle | Label text color |
font | TLDefaultFontStyle | Font family for the label |
scale | number | Scale factor applied to the shape |
When a user draws an arrow onto a shape, the editor creates an arrow binding: a record that connects one of the arrow's terminals to the target shape. The arrow recalculates its path whenever the bound shape moves, resizes, or rotates. When a terminal is bound, the editor computes its position from the binding and ignores the corresponding start or end prop.
To bind an arrow programmatically, create a binding of type arrow from the arrow to the target shape:
editor.createBinding({
type: 'arrow',
fromId: arrow.id,
toId: targetShape.id,
props: {
terminal: 'end',
normalizedAnchor: { x: 0.5, y: 0.5 },
isPrecise: false,
isExact: false,
snap: 'none',
},
})
An arrow can have up to two bindings, one with terminal: 'start' and one with terminal: 'end'. Use getArrowBindings to read an arrow's current bindings. See Bindings for how bindings work in general, and the create arrow example for a complete implementation.
Three binding props control where the arrow attaches. See TLArrowBindingProps for details.
| Prop | Effect |
|---|---|
normalizedAnchor | The attachment point within the shape's bounds, where { x: 0, y: 0 } is the top-left corner and { x: 1, y: 1 } is the bottom-right |
isPrecise | When true, the arrow points at the normalizedAnchor position. When false, it points at the shape's center |
isExact | When true, the arrowhead travels all the way to the anchor point, entering the shape. When false, the arrow stops at the edge of the shape's geometry |
When drawing with the arrow tool, users get imprecise center bindings by default. Hovering over a spot inside a shape for a moment, pausing while dragging a terminal, or holding Alt switches to a precise binding at that spot. The hoverPreciseTimeout and pointingPreciseTimeout options control the delays, and holding Ctrl skips binding entirely (shouldIgnoreTargets).
The kind prop selects between the two routing modes. It's a style prop, so users can switch modes from the style panel.
Arc arrows (kind: 'arc', the default) draw a straight line or a circular arc between their terminals. The bend prop is the perpendicular distance from the straight line to the arc's midpoint: 0 draws a straight line, positive and negative values curve to either side. Users adjust the bend by dragging the arrow's middle handle.
Elbow arrows (kind: 'elbow') route with right-angled segments, like connectors in a flowchart. The elbowMidPoint prop (0–1) positions the middle segment between the two ends. The binding's snap prop records what the terminal snapped to when drawn: 'center', 'edge', 'edge-point', or 'none'. The edge values are only produced for elbow arrows, which use them when routing.
The arrowheadStart and arrowheadEnd props set the style of each end independently. The available styles are arrow, triangle, square, dot, pipe, diamond, inverted, bar, and none. By default, arrows have none at the start and arrow at the end.
editor.updateShape({
id: arrow.id,
type: 'arrow',
props: {
arrowheadStart: 'dot',
arrowheadEnd: 'triangle',
},
})
Arrows can have a rich text label, stored in the richText prop. Use toRichText to create one from a plain string. The labelPosition prop (0–1) places the label along the arrow's path, with 0.5 (the default) at the midpoint. Users can drag the label along the arrow to reposition it. The labelColor and font props style the label's text.
ArrowShapeUtil exposes options for tuning arrow behavior, like snap distances, precise-targeting timeouts, and whether new arrows bind exactly. Use the static configure method to override them:
import { ArrowShapeUtil, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
const shapeUtils = [
ArrowShapeUtil.configure({
// Precise arrows point exactly at the spot the user picked
shouldBeExact: (editor, isPrecise) => isPrecise,
}),
]
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw shapeUtils={shapeUtils} />
</div>
)
}
See ArrowShapeOptions for the full list of options.