Files
upstream-tldraw/apps/docs/content/sdk-features/styles.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

209 lines
9.3 KiB
Plaintext

---
title: Styles
created_at: 12/20/2025
updated_at: 12/20/2025
keywords:
- styles
- StyleProp
- color
- opacity
- shared styles
- design system
- appearance
status: published
date: 12/20/2025
readability: 9
voice: 9
completeness: 9
accuracy: 10
notes: ''
---
The styles system manages visual properties like color, size, font, fill, and dash patterns across shapes. Style properties differ from regular shape properties in two ways: the same value can be set on many shapes at once, and the editor remembers the last-used value and applies it to newly created shapes.
Styles are defined using [StyleProp](?) instances that specify valid values and defaults. The editor tracks "shared styles" across the current selection (whether all selected shapes share the same value or have different values) to drive the UI and enable batch updates.
## How it works
### StyleProp
A [StyleProp](?) represents a reusable style property that can be applied across different shape types. Each `StyleProp` has a unique identifier, a default value, and optional validation.
You define a `StyleProp` using one of two static methods, [StyleProp#define](?) for arbitrary types and [StyleProp#defineEnum](?) for a fixed list of values:
```typescript
import { StyleProp, T } from 'tldraw'
// Define a numeric style property
const LineWidthStyle = StyleProp.define('myApp:lineWidth', {
defaultValue: 2,
type: T.number,
})
// Define an enumerated style property
const CapStyle = StyleProp.defineEnum('myApp:cap', {
defaultValue: 'round',
values: ['round', 'square', 'butt'],
})
```
The unique identifier should be namespaced to avoid conflicts with other style properties. Use your app or library name as a prefix.
### Shape integration
To use a style property in your shape, include the `StyleProp` instance in your shape's props definition. This works the same way for your own styles and for tldraw's defaults. The editor recognizes `StyleProp` instances and handles them specially: it saves their values, applies them to new shapes, and tracks them across selections.
```typescript
import {
DefaultColorStyle,
DefaultSizeStyle,
RecordProps,
T,
TLDefaultColorStyle,
TLDefaultSizeStyle,
TLShape,
} from 'tldraw'
// Register the shape type and its props
declare module 'tldraw' {
export interface TLGlobalShapePropsMap {
'my-shape': {
w: number
h: number
color: TLDefaultColorStyle
size: TLDefaultSizeStyle
lineWidth: number
}
}
}
type TLMyShape = TLShape<'my-shape'>
// Pass StyleProp instances in the props object for validation
const myShapeProps: RecordProps<TLMyShape> = {
w: T.number,
h: T.number,
color: DefaultColorStyle,
size: DefaultSizeStyle,
lineWidth: LineWidthStyle,
}
```
When you create a shape, provide the actual style values. If you omit a style prop, the editor uses its saved value from previous shapes:
```typescript
editor.createShape({
type: 'my-shape',
props: {
w: 100,
h: 100,
color: 'red',
size: 'm',
},
})
```
### Shared styles
The editor computes shared styles across the current selection. Use [Editor#getSharedStyles](?) to get a [ReadonlySharedStyleMap](?) from each style property to its [SharedStyle](?) status: either "shared" (all shapes have the same value) or "mixed" (shapes have different values).
```typescript
const sharedStyles = editor.getSharedStyles()
const colorStyle = sharedStyles.get(DefaultColorStyle)
if (colorStyle && colorStyle.type === 'shared') {
console.log('All shapes are', colorStyle.value)
} else if (colorStyle && colorStyle.type === 'mixed') {
console.log('Shapes have different colors')
}
```
For convenience, use `getAsKnownValue` when you only care about the shared case:
```typescript
const sharedStyles = editor.getSharedStyles()
const color = sharedStyles.getAsKnownValue(DefaultColorStyle)
// Returns the color if all shapes share it, undefined otherwise
```
The `getSharedStyles` method examines each selected shape, extracts its style values, and compares them. For groups, it recursively examines the group's children rather than the group itself, since groups don't have visual styles.
When you're not in the select tool with a selection, `getSharedStyles` returns the styles for the current tool if that tool creates shapes. This lets the UI show and modify the styles that will be applied to the next shape.
### Setting styles
Use [Editor#setStyleForSelectedShapes](?) to change styles on the current selection:
```typescript
// Change color for all selected shapes
editor.setStyleForSelectedShapes(DefaultColorStyle, 'red')
// Change size
editor.setStyleForSelectedShapes(DefaultSizeStyle, 'l')
```
This method recursively applies the style to all shapes in the selection, including shapes nested inside groups. It only updates shapes that support the given style property.
Use [Editor#setStyleForNextShapes](?) to change the style for subsequently created shapes, and [Editor#getStyleForNextShape](?) to read it:
```typescript
// Next shapes will be blue
editor.setStyleForNextShapes(DefaultColorStyle, 'blue')
// Create a new shape - it will be blue
editor.createShape({ type: 'geo', props: { w: 100, h: 100 } })
const nextColor = editor.getStyleForNextShape(DefaultColorStyle) // 'blue'
```
`setStyleForSelectedShapes` only updates the selected shapes; it does not change the value for next shapes. The style panel calls both methods when the user picks a value, so the change applies to the selection and carries over to the next shape. Do the same in your own code if you want that behavior:
```typescript
editor.run(() => {
editor.setStyleForSelectedShapes(DefaultColorStyle, 'blue')
editor.setStyleForNextShapes(DefaultColorStyle, 'blue')
})
```
## Default styles
The `@tldraw/tlschema` package provides a set of default style properties that the built-in shapes use. Colors reference theme values rather than raw hex codes, so shapes adapt to light and dark modes.
| Style | Values | Used for |
| ---------------------------------- | ----------------------------------------------------- | ------------------------------------------ |
| [DefaultColorStyle](?) | black, red, blue, green, and other named colors | Primary shape color |
| [DefaultFillStyle](?) | none, semi, solid, pattern, fill, lined-fill | Fill pattern |
| [DefaultDashStyle](?) | draw, solid, dashed, dotted, none | Stroke style |
| [DefaultSizeStyle](?) | s, m, l, xl | Relative size scale |
| [DefaultFontStyle](?) | draw, sans, serif, mono | Font family |
| [DefaultTextAlignStyle](?) | start, middle, end | Horizontal text alignment |
| [DefaultHorizontalAlignStyle](?) | start, middle, end | Horizontal content alignment within bounds |
| [DefaultVerticalAlignStyle](?) | start, middle, end | Vertical content alignment within bounds |
| [GeoShapeGeoStyle](?) | rectangle, ellipse, triangle, and other geo types | Geometric shape type |
| [ArrowShapeArrowheadStartStyle](?) | arrow, triangle, dot, none, and other arrowhead types | Start arrowhead |
| [ArrowShapeArrowheadEndStyle](?) | Same values as the start style | End arrowhead |
| [ArrowShapeKindStyle](?) | arc, elbow | Arrow routing |
| [LineShapeSplineStyle](?) | line, cubic | Line spline type |
The shape-specific styles are defined in `@tldraw/tlschema` next to their shape's record type.
Opacity is not a `StyleProp`. It's a regular property on the base shape ([TLBaseShape](?)) that all shapes inherit, but it behaves like a style through its own methods: [Editor#getSharedOpacity](?), [Editor#setOpacityForSelectedShapes](?), and [Editor#setOpacityForNextShapes](?).
## Customizing default styles
Change the default value of any style with `setDefaultValue`. Enum styles also support `addValues` and `removeValues` for extending the built-in set at runtime:
```typescript
import { DefaultSizeStyle } from 'tldraw'
DefaultSizeStyle.setDefaultValue('s')
```
## Related examples
- [Custom shape with custom styles](/examples/shapes/tools/shape-with-custom-styles) - Create your own custom styles and use them in custom shapes.
- [Custom shape with tldraw styles](/examples/shapes/tools/shape-with-tldraw-styles) - Use tldraw's default styles in your custom shapes and integrate with the style panel.
- [Change default styles](/examples/ui/changing-default-style) - Change the default value for a style property (e.g., setting size to small by default).
- [Change default colors](/examples/ui/changing-default-colors) - Customize the color values in the tldraw theme.
- [Easter egg styles](/examples/editor-api/easter-egg-styles) - Access hidden styles like white color, special fill variants, and label colors programmatically.