Styles
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 key ways: they apply consistently across multiple shapes at once, and the editor remembers the last-used value to automatically apply it to newly created shapes. This creates a coherent visual experience where users can set a color once and have it persist across their work.
Styles are defined using StyleProp instances that specify valid values and defaults. The editor tracks "shared styles" across the current selection—computing 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. The editor treats StyleProp instances specially, automatically saving their values and applying them to new shapes.
You define a StyleProp using one of two static methods:
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. The editor recognizes StyleProp instances and handles them specially: it saves their values, applies them to new shapes, and tracks them across selections.
import { DefaultColorStyle, DefaultSizeStyle, RecordProps, T, TLBaseShape } from 'tldraw'
// Define your shape type with the value types for styles
type TLMyShape = TLBaseShape<
'my-shape',
{
w: number
h: number
color: string // Will be one of the default color names
size: string // Will be one of the default size values
}
>
// Pass StyleProp instances in the props object for validation
const myShapeProps: RecordProps<TLMyShape> = {
w: T.number,
h: T.number,
color: DefaultColorStyle,
size: DefaultSizeStyle,
}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:
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 map of each style property to its status: either "shared" (all shapes have the same value) or "mixed" (shapes have different values).
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:
const sharedStyles = editor.getSharedStyles()
const color = sharedStyles.getAsKnownValue(DefaultColorStyle)
// Returns the color if all shapes share it, undefined otherwiseThe 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 no shapes are selected, 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.
Style persistence
When you set a style on selected shapes, the editor saves that value as the "style for next shapes." The next shape you create will automatically have the same style value.
// Set color for selected shapes - also saves it for next shapes ([`Editor.setStyleForSelectedShapes`](/reference/editor/Editor#setStyleForSelectedShapes))
editor.setStyleForSelectedShapes(DefaultColorStyle, 'blue')
// Create a new shape - it will be blue because 'blue' was saved
editor.createShape({ type: 'geo', props: { w: 100, h: 100 } })You can set the style for next shapes without affecting the current selection using Editor.setStyleForNextShapes:
editor.setStyleForNextShapes(DefaultColorStyle, 'green')Default styles
The @tldraw/tlschema package provides a set of default style properties that the built-in shapes use. These styles cover the most common visual properties and integrate with tldraw's theme system for consistent appearance.
Color styles control the visual color of shapes and their labels. Colors reference theme values rather than raw hex codes, allowing shapes to adapt to light and dark modes.
DefaultColorStyle- Primary shape color (black, red, blue, green, etc.)DefaultLabelColorStyle- Label text color for shapes
Appearance styles affect how shapes are drawn and filled. These work together to create the hand-drawn aesthetic that defines tldraw's visual style.
DefaultFillStyle- Fill pattern (none, semi, solid, pattern, fill, lined-fill)DefaultDashStyle- Stroke style (draw, solid, dashed, dotted)DefaultSizeStyle- Relative size scale (s, m, l, xl)
Text styles control typography for text shapes and labels. The alignment styles handle both the text itself and how content positions within shape bounds.
DefaultFontStyle- Font family (draw, sans, serif, mono)DefaultTextAlignStyle- Horizontal text alignment (start, middle, end)DefaultHorizontalAlignStyle- Horizontal content alignment within boundsDefaultVerticalAlignStyle- Vertical content alignment within bounds
Shape-specific styles apply to particular shape types rather than being universal. These are defined alongside their respective shape utilities.
GeoShapeGeoStyle- Geometric shape type (rectangle, ellipse, triangle, etc.)ArrowShapeArrowheadStartStyle- Start arrowhead typeArrowShapeArrowheadEndStyle- End arrowhead type
Note that opacity is not a style property. It's a regular property on the base shape (TLBaseShape) that all shapes inherit, and it doesn't persist to new shapes or sync across selections like style properties do.
Using styles
Getting styles
Use getSharedStyles to examine the current selection's styles:
const styles = editor.getSharedStyles()
// Check if all shapes share a color
const color = styles.get(DefaultColorStyle)
if (color?.type === 'shared') {
console.log('Shared color:', color.value)
}To get the style value for the next shape to be created, use Editor.getStyleForNextShape:
const nextColor = editor.getStyleForNextShape(DefaultColorStyle)Setting styles
Use Editor.setStyleForSelectedShapes to change styles on the current selection:
// 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:
// Next shapes will be blue
editor.setStyleForNextShapes(DefaultColorStyle, 'blue')Custom styles
You can create custom style properties for your shapes using StyleProp.define or StyleProp.defineEnum.
Defining a custom style
For numeric or complex types, use StyleProp.define:
import { StyleProp, T } from 'tldraw'
export const MyLineWidthStyle = StyleProp.define('myApp:lineWidth', {
defaultValue: 2,
type: T.number,
})For enumerated values, use StyleProp.defineEnum:
export const MyPatternStyle = StyleProp.defineEnum('myApp:pattern', {
defaultValue: 'solid',
values: ['solid', 'striped', 'dotted', 'checkered'],
})Using custom styles in shapes
Include your custom style in your shape's props definition:
import { RecordProps, T, TLBaseShape } from 'tldraw'
type TLMyShape = TLBaseShape<
'my-shape',
{
w: number
h: number
lineWidth: number
pattern: string
}
>
const myShapeProps: RecordProps<TLMyShape> = {
w: T.number,
h: T.number,
lineWidth: MyLineWidthStyle,
pattern: MyPatternStyle,
}The editor automatically recognizes StyleProp instances in your props and handles them during shape creation, selection, and updates.
Related examples
- Custom shape with custom styles - Create your own custom styles and use them in custom shapes.
- Custom shape with tldraw styles - Use tldraw's default styles in your custom shapes and integrate with the style panel.
- Change default styles - Change the default value for a style property (e.g., setting size to small by default).
- Change default colors - Customize the color values in the tldraw theme.
- Custom stroke and font sizes - Override the default stroke and font size values.
- Easter egg styles - Access hidden styles like white color, special fill variants, and label colors programmatically.