snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
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

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
---
title: Frame shape
created_at: 1/31/2026
updated_at: 5/6/2026
keywords:
- frame
- container
- artboard
- clipping
- frame tool
- BaseFrameLikeShapeUtil
status: published
date: 5/6/2026
---
The frame shape is a container with a labeled header that holds other shapes. Children of a frame are clipped to its bounds, follow the frame when it moves, and export together as a single image. Frames are useful for laying out artboards, screen mockups, slides, and any visual region that should travel as one unit. See [FrameShapeUtil](?) and [TLFrameShape](?).
```tsx
editor.createShape({
type: 'frame',
x: 100,
y: 100,
props: {
w: 800,
h: 600,
name: 'Login screen',
color: 'black',
},
})
```
## Creating frames
You can create a frame programmatically with [Editor#createShape](?), or interactively with the frame tool. The frame tool ships in the default toolbar; users can also press `F` to switch to it. The **Frame selection** action (`Cmd/Ctrl+Alt+G`) wraps the current selection in a new frame.
When the user drags a frame around existing shapes, the frame tool reparents any sibling shapes that fall fully inside the frame's bounds. Locked shapes are skipped. This is what makes "draw a frame around the things I want to group" work as a single gesture.
Children inside a frame use coordinates relative to the frame's origin. Moving the frame moves every descendant; rotating the frame rotates them too.
## Frame header
Every frame renders a heading above its top edge that displays the frame's `name` property. Click the heading to edit the name; pressing Enter with a frame selected does not enter edit mode. The heading rotates with the frame to stay above whichever edge is currently "up", so it remains readable.
Empty names render as `Frame` so unnamed frames still get a label. The shape's `name` is also exposed via [ShapeUtil#getAriaDescriptor](?) so screen readers announce it during keyboard navigation.
## Child clipping
Frames clip their children to the frame's rectangle during rendering. A shape that extends past the frame edge is rendered up to the boundary and then cut off. Clipping doesn't change the child's geometry or its own bounds, but hit testing respects the mask: you can't click the clipped-off part of a shape, and [Editor#getShapeMaskedPageBounds](?) returns only the visible portion. Arrows are exempt from clipping so connectors can leave a frame.
The [BaseFrameLikeShapeUtil](?) base class implements clipping via `getClipPath` and the arrow exemption via `shouldClipChild`. If you need clipping for a custom container shape, see the [Frames](/sdk-features/shapes#Frames) section in the Shapes guide.
## Shape properties
| Property | Type | Description |
| -------- | --------------------- | ---------------------------------------------------- |
| `w` | `number` | Frame width in pixels (default: `320`) |
| `h` | `number` | Frame height in pixels (default: `180`) |
| `name` | `string` | Label displayed in the frame header |
| `color` | `TLDefaultColorStyle` | Color for the border and heading (when `showColors`) |
## Configuration options
`FrameShapeUtil` exposes two configuration options:
| Option | Type | Default | Description |
| ---------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------- |
| `showColors` | `boolean` | `false` | When true, frames display a colored border and header background based on the frame's `color` property. |
| `resizeChildren` | `boolean` | `false` | When true, resizing a frame scales its children proportionally instead of leaving them in place. |
```tsx
import { FrameShapeUtil, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
const ConfiguredFrameUtil = FrameShapeUtil.configure({
showColors: true,
resizeChildren: true,
})
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw shapeUtils={[ConfiguredFrameUtil]} />
</div>
)
}
```
When `showColors` is on, `color` becomes a real style property: users can change it from the style panel and it syncs across selections like other styles. With `showColors` off (the default), `color` still validates and persists, but the frame renders with a neutral palette so it doesn't compete visually with the shapes inside it.
## Frame helpers
The editor exposes helpers that work with frames and any other shape that opts into frame-like behavior. Use [Editor#isShapeFrameLike](?) to check whether a shape is a frame or a custom frame-like shape.
### Fitting a frame to its content
[fitFrameToContent](?) resizes a frame so it tightly wraps its children, with a configurable padding (50 by default). Double-clicking a frame's corner handle does the same with a padding of 10; double-clicking an edge handle fits only that axis.
```tsx
import { fitFrameToContent } from 'tldraw'
fitFrameToContent(editor, frameId)
// Or with a custom padding
fitFrameToContent(editor, frameId, { padding: 24 })
```
### Removing a frame
[removeFrame](?) deletes a frame but preserves its children: they're moved out of the frame and reselected.
```tsx
import { removeFrame } from 'tldraw'
removeFrame(editor, [frameId])
```
The **Remove frame** and **Fit frame to content** actions in the main menu and the context menu's Edit submenu call these helpers when a frame is selected. **Frame selection** (`Cmd/Ctrl+Alt+G`) also removes frames when every selected shape is a frame.
## Exporting frames
Frames are export bounds containers: [ShapeUtil#isExportBoundsContainer](?) returns `true`. When a frame contains all the other shapes in an export, the export pipeline skips the usual padding around the result and uses the frame's bounds exactly. The export still includes every descendant of the frame.
This suits mockup workflows where you need output at a specific aspect ratio: design the frame, drop content inside, export.
## Frames vs. groups
Frames and groups both contain other shapes, but they solve different problems:
| | Frame | Group |
| ---------------------------- | ---------------------------------------- | --------------------------------------- |
| Visible on the canvas | Yes, a bordered rectangle with a heading | No |
| Clips children to its bounds | Yes | No |
| Has a fixed size and shape | Yes (`w`, `h`, position) | No (geometry follows children) |
| Used for export bounds | Yes | No |
| Auto-deletes when empty | No | Yes (collapses at one or zero children) |
| Created by | Frame tool or `editor.createShape` | [Editor#groupShapes](?) |
Reach for a frame when you want a labeled, bounded region: a slide, a screen, an artboard. Reach for a group when you need to move several shapes together without changing their visual layout.
## Related articles
- [Shapes](/sdk-features/shapes#Frames) — How to build your own container shape with `BaseFrameLikeShapeUtil`
- [Default shapes](/sdk-features/default-shapes#Frame) — Overview of all built-in shapes
- [Shape clipping](/sdk-features/shape-clipping) — How custom shapes can clip their children
- [Image export](/sdk-features/image-export) — Exporting frames and selections as images
- [Parenting](/sdk-features/parenting) — How shapes are nested inside containers
## Related examples
- [Portal shapes](/examples/shapes/tools/portal-shapes) — A custom frame-like shape that teleports children between instances