apps/docs/content/sdk-features/note-shape.mdx
The note shape is a sticky note: a colored square with text. Notes are built for brainstorming: you can spawn new notes next to existing ones with clone handles or keyboard shortcuts, and they snap into a grid beside their neighbors. See NoteShapeUtil and TLNoteShape.
import { toRichText } from 'tldraw'
editor.createShape({
type: 'note',
x: 100,
y: 100,
props: {
color: 'yellow',
labelColor: 'black',
richText: toRichText('My note'),
size: 'm',
font: 'draw',
align: 'middle',
verticalAlign: 'middle',
},
})
Notes have a fixed base width of 200 pixels (the noteWidth display value). Unlike most shapes, you can't manually resize a note by default. Instead, notes grow vertically to fit their text. The growY property tracks how much extra height the note needs beyond its base size.
When text is too wide, the note shrinks the font size (down to a minimum of 14px) before allowing text to wrap. This keeps notes compact without hiding content.
Notes display clone handles on their edges—small plus buttons at the top, right, bottom, and left sides. These handles let you quickly create adjacent notes.
Click a clone handle to create a new note in that direction. If a note already exists there, tldraw selects it and starts editing instead. Drag a clone handle to create a new note and immediately start moving it; when you release, the new note enters edit mode.
Clone handles only appear when the note is selected and the effective zoom (zoom × note scale) is high enough. Below 25% they're hidden entirely, and between 25% and 50% only the bottom handle appears. Touch input never shows clone handles.
The handles come from ShapeUtil#getHandles: each has type: 'clone' and an id of top, right, bottom, or left.
When you create a note with the note tool (N key) or drag an existing note, tldraw checks whether you're near an "adjacent position": an empty slot next to another note. If you're within 10 screen pixels of a slot, the note snaps into place with consistent spacing.
Snapping only considers notes with the same scale. New notes created with the tool only snap next to unrotated notes; dragged notes snap next to notes with matching rotation. The spacing comes from editor.options.adjacentShapeMargin (10 pixels by default; see TldrawOptions).
When editing a note, you can use keyboard shortcuts to create adjacent notes:
| Shortcut | Action |
|---|---|
| Tab | Create or select note right |
| Shift+Tab | Create or select note left |
| Cmd/Ctrl+Enter | Create or select note below |
| Shift+Cmd/Ctrl+Enter | Create or select note above |
These shortcuts respect the current note's rotation. They also handle right-to-left text: in RTL content, Tab moves left instead of right. When the cursor is inside a list, Tab indents the list item instead of creating a note.
When moving down, the keyboard shortcut accounts for the current note's growY. This keeps notes from overlapping when one note has grown taller than the base size.
Notes render with a subtle drop shadow seeded from the shape's ID, so each note has slightly different lift and opacity. The shadow responds to the note's rotation on the canvas. Below 25% effective zoom (adjusted for the note's scale) the shadow is replaced with a plain bottom border to keep rendering cheap.
The note's text color is determined by its labelColor property. When set to 'black' (the default), the note uses a color that contrasts well with the background. Other label colors override this automatic selection.
| Property | Type | Description |
|---|---|---|
color | TLDefaultColorStyle | Background color of the note |
labelColor | TLDefaultColorStyle | Text color (independent of background) |
richText | TLRichText | Note content with formatting |
size | TLDefaultSizeStyle | Size preset (s, m, l, xl) affecting base font |
font | TLDefaultFontStyle | Font family (draw, sans, serif, mono) |
align | TLDefaultHorizontalAlignStyle | Horizontal text alignment |
verticalAlign | TLDefaultVerticalAlignStyle | Vertical text alignment |
fontSizeAdjustment | number | null | Ratio applied to the base font size when text shrinks to fit (set automatically) |
growY | number | Additional height beyond the base 200px (set automatically) |
url | string | Optional hyperlink URL |
scale | number | Scale factor applied to the shape |
textLastEditedBy | string | null | ID of the user who last edited the note's text (set automatically) |
Notes support the following configuration options:
| Option | Type | Default | Description |
|---|---|---|---|
resizeMode | 'none' | 'scale' | 'none' | How the note resizes. Set to 'scale' for manual resize handles. |
By default, notes can't be manually resized—they only grow based on text content. To allow user resizing with locked aspect ratio:
import { Tldraw, NoteShapeUtil } from 'tldraw'
import 'tldraw/tldraw.css'
const ConfiguredNoteUtil = NoteShapeUtil.configure({
resizeMode: 'scale',
})
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw shapeUtils={[ConfiguredNoteUtil]} />
</div>
)
}
See the note resizing example for a working demo. Other display values, such as noteWidth, noteHeight, and colors, can be customized through the display value hooks on NoteShapeUtil options; see Themes.
When editor.user.getIsDynamicResizeMode() is true, new notes are created at a scale inversely proportional to the current zoom level, so they stay visually consistent regardless of zoom. Editor#getResizeScaleFactor returns that scale. See Text shape for details.