Files
upstream-tldraw/apps/docs/content/sdk-features/note-shape.mdx
upstream-mirror a774ac673a
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
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

140 lines
8.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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