[]previous and next page

Styles and themes

How styles flow from the panel to shapes, why colors are tokens, and how to give CanvasFlow your own palette.

Styles#

A style is a prop that many shapes share under the same name: color, fill, size, dash, sketch, font, fontSize, align, dir, edges, arrowKind, arrowheadStart, arrowheadEnd. A shape supports a style when its default props contain that key.

setStyle does two things at once. It changes the selected shapes that support the style, and it remembers the value for the next shape you create:

ts
editor.setStyle('color', 'blue') // selected shapes turn blue, and so will the next one
editor.setStyle('sketch', 0) // crisp, architect-style lines from now on
editor.setOpacity(0.6)

editor.getSharedStyles() returns each style for the current selection, with mixed: true when the selection disagrees. That's what the style panel shows.

Sloppiness and fill#

sketch: 0
sketch: 1
sketch: 2
Sloppiness 0, 1 and 2. The jitter is seeded per shape, so a shape never “boils” while you edit it.

Hand-drawn jitter is seeded per shape, so a shape looks the same every time it renders. It never "boils" while you drag it, and it looks the same on every collaborator's screen.

dir is the direction of a shape's text (auto, ltr or rtl). See Right to left.

Copy and paste styles#

ts
editor.copyStyles() // ⌘⌥C
editor.pasteStyles() // ⌘⌥V

Colors are tokens#

Shapes store color names like blue or violet, not hex values. The theme decides what blue looks like. That's why switching to dark mode never rewrites a document, and why a board made in light mode looks right in dark mode for someone else.

The twelve tokens are black, grey, white, red, orange, yellow, green, teal, blue, violet, pink and brown. A shape can also store any CSS color (the panel's custom color picker does this), which then looks the same in every theme.

Themes#

ts
editor.setTheme('dark')
editor.state.theme // 'dark'

On the web, followSystemTheme: true tracks the operating system until the person picks a theme themselves.

Your own palette#

A theme is a plain object. Start from the built-in one and change what you need:

theme.tsts
import { darkTheme, lightTheme, type Theme } from 'canvasflow'
import { createCanvasFlow } from 'canvasflow/dom'

const paper: Theme = {
  ...lightTheme,
  background: '#fbf8f3',
  accent: '#e8590c',
  accentSoft: 'rgba(232, 89, 12, 0.12)',
}

const ink: Theme = { ...darkTheme, background: '#17140f', accent: '#ff8a4c', accentSoft: 'rgba(255, 138, 76, 0.16)' }

createCanvasFlow(document.getElementById('board')!, { themes: { light: paper, dark: ink } })

The theme covers the canvas background, text, the accent used for selection and handles, the grid, frame colors, and what each color token resolves to.

CSS variables#

The web renderer exposes the theme as CSS custom properties on the canvas root (--cf-background, --cf-accent, --cf-c-blue and friends), and the SVG references them. A theme switch is a variable change, not a re-render. You can also use them in your own UI to match the canvas.

Fonts#

The font style picks one of four families by name: hand, sans, serif and mono. The web host resolves them through FONT_STACKS. The hand-drawn stack starts with Virgil and Excalifont, so load one of them with @font-face for the classic sketchy look, or put your own font first.