Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
140 lines
8.5 KiB
Plaintext
140 lines
8.5 KiB
Plaintext
---
|
||
title: Note shape
|
||
created_at: 1/31/2026
|
||
updated_at: 1/31/2026
|
||
keywords:
|
||
- note
|
||
- sticky note
|
||
- note tool
|
||
- clone handles
|
||
- adjacent notes
|
||
status: published
|
||
date: 1/31/2026
|
||
---
|
||
|
||
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](?).
|
||
|
||
```tsx
|
||
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',
|
||
},
|
||
})
|
||
```
|
||
|
||
## Sizing behavior
|
||
|
||
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.
|
||
|
||
## Clone handles
|
||
|
||
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`.
|
||
|
||
## Adjacent snapping
|
||
|
||
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](?)).
|
||
|
||
## Keyboard navigation
|
||
|
||
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.
|
||
|
||
## Visual appearance
|
||
|
||
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.
|
||
|
||
## Properties
|
||
|
||
| 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) |
|
||
|
||
## Configuration
|
||
|
||
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. |
|
||
| `AttributionComponent` | `ComponentType<TLNoteShapeAttributionProps>` \| `null` | `DefaultNoteShapeAttribution` | Component for the attribution badge. Set to `null` to hide it, or provide your own to replace it. |
|
||
|
||
By default, notes can't be manually resized—they only grow based on text content. To allow user resizing with locked aspect ratio:
|
||
|
||
```tsx
|
||
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](/examples/configuration/resize-note) 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](/sdk-features/themes).
|
||
|
||
### Attribution badge
|
||
|
||
Notes show the name of the user who last edited their text as a small badge in the corner. This badge is rendered by the `AttributionComponent` option above, which you can override or hide with `NoteShapeUtil.configure`—it applies on the canvas and in image exports. See [attribution](/sdk-features/attribution) for details.
|
||
|
||
## Dynamic resize mode
|
||
|
||
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](/sdk-features/text-shape#Dynamic-resize-mode) for details.
|
||
|
||
## Related articles
|
||
|
||
- [Attribution](/sdk-features/attribution) — How notes display who last edited them in multiplayer sessions
|
||
- [Default shapes](/sdk-features/default-shapes) — Overview of all built-in shapes
|
||
- [Rich text](/sdk-features/rich-text) — Working with formatted text content
|
||
- [Styles](/sdk-features/styles) — Working with shape styles like color and size
|