Polotno Docs
API

Element

Elements represent graphical objects in a page or group

Element represents a graphical object on the page or inside a group. An element can have one of these types:

  • text
  • image
  • svg
  • line
  • figure
  • video
  • group
const element = store.activePage.addElement({
  type: 'text',
  x: 50,
  y: 50,
  fill: 'black',
  text: 'hello',
});

// logs 50
console.log(element.x);

// set new position
element.set({ x: 100 });

Basic actions

Read properties

At any time, you can access any property of an element. See documentation for every element type to view all available properties.

const element = store.selectedElements[0];
// logs type of element
console.log(element.type);
// logs id of element
console.log(element.id);

element.set(attrs)

Set new attributes to the element.

text.set({ x: text.x + 10, text: 'new text' });

Custom properties

You can't write any arbitrary property directly on an element. If you want to store additional data, use the custom attribute.

// 🛑 this line will not work, because elements have no attribute `userId`
element.set({ userId: '12' });
// 🟢 you can write such data into "custom" attribute
element.set({ custom: { userId: '12' } });
// read custom attribute
console.log(element.custom?.userId);

element.moveUp()

Move element up on z-index.

text.moveUp();

element.moveDown()

Move element down on z-index.

text.moveDown();

element.moveTop()

Move element to the top of the page or a group.

text.moveTop();

element.moveBottom()

Move element to the bottom of the page or a group.

text.moveBottom();

Locking

Use draggable, contentEditable, styleEditable, removable and resizable attributes to lock element editing.

// lock the object
element.set({
  // can element be moved and rotated
  draggable: false,
  // can we change content of element?
  contentEditable: false,
  // can we change style of element?
  styleEditable: false,
  // can we resize element?
  resizable: false,
  // can we remove an element?
  removable: false,
});

console.log(element.locked); // true

// unlock it
element.set({
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,
  // can we change style of element?
  styleEditable: true,
  // can we resize element?
  resizable: true,
  removable: true,
});

Text element

Text elements allow you to create text on the canvas.

Here is the example of default properties:

page.addElement({
  type: 'text',
  x: 0,
  y: 0,
  rotation: 0,
  locked: false, // deprecated
  blurEnabled: false,
  blurRadius: 10,
  brightnessEnabled: false,
  brightness: 0,
  shadowEnabled: false,
  shadowBlur: 5,
  shadowOffsetX: 0,
  shadowOffsetY: 0,
  shadowColor: 'black',
  shadowOpacity: 1,
  name: '', // name of element, can be used to find element in the store
  text: 'Hey, polotno',
  // placeholder is working similar to input placeholder
  // it will be rendered if no text is defined
  // and we will use it in input element too
  // useful for template canvas, where users will need to replace text elements
  // important (!) placeholders are removed from export result
  placeholder: '',
  fontSize: 14,
  fontFamily: 'Roboto',
  fontStyle: 'normal', // can be normal or italic
  fontWeight: 'normal', // can be normal or bold or some other CSS variations
  textDecoration: '',
  fill: 'black',
  align: 'center',
  width: 0,
  strokeWidth: 0,
  stroke: 'black',
  lineHeight: 1,
  letterSpacing: 0, // % from font size,
  backgroundEnabled: false,
  backgroundColor: '#7ED321',
  backgroundOpacity: 1,
  backgroundCornerRadius: 0.5, // % from half line height
  backgroundPadding: 0.5, //% from half line height

  // can user select element?
  // if false, element will be "invisible" for user clicks
  selectable: true,
  // use for absolute positing of element
  alwaysOnTop: false,
  // also we can hide some elements from the export
  showInExport: true,
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,
  // can we remove element from UI with button or keyboard?
  removable: true,
  // can we resize element?
  resizable: true,
  // can we change style of element?
  styleEditable: true,
});

text.toggleEditMode()

Enable edit mode for the text. It puts the cursor inside the text and a user can do regular text editing. You can call text.toggleEditMode() programmatically (e.g. right after creating a new text element).

Image element

Image element draws an image on the canvas. By default images do smart-cropping to fit into its size.

page.addElement({
  type: 'image',
  x: 0,
  y: 0,
  rotation: 0,
  locked: false, // deprecated
  blurEnabled: false,
  blurRadius: 10,
  brightnessEnabled: false,
  brightness: 0,
  shadowEnabled: false,
  shadowBlur: 5,
  shadowOffsetX: 0,
  shadowOffsetY: 0,
  shadowColor: 'black',
  shadowOpacity: 1,
  name: '', // name of element, can be used to find element in the store
  // url path to image
  src: 'https://example.com/image.png',
  keepRatio: false, // can we change aspect ratio of element on resize
  stretchEnabled: false, // can we stretch image on any axis

  // url path to svg or image that will be used to clip image
  // can be used for image framing
  clipSrc: '',
  width: 100,
  height: 100,
  cropX: 0, // 0-1 : % from original image width
  cropY: 0, // 0-1 : % from original image height
  cropWidth: 1, // 0-1 : % from original image width
  cropHeight: 1, // 0-1 : % from original image height
  cornerRadius: 0,
  borderColor: 'black',
  borderSize: 0,
  flipX: false,
  flipY: false,

  // can user select element?
  // if false, element will be "invisible" for user clicks
  selectable: true,
  // use for absolute positing of element
  alwaysOnTop: false,
  // also we can hide some elements from the export
  showInExport: true,
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,

  // can we remove element from UI with button or keyboard?
  removable: true,
  // can we resize element?
  resizable: true,
});

image.toggleCropMode()

Enter into "crop mode" of the image programmatically.

<Button
  minimal
  icon={<Crop />}
  // use capture handler to handle click event sooner
  onClickCapture={(e) => {
    // stop propagation to prevent autohide of crop mode on current click
    e.stopPropagation();
    element.toggleCropMode(true);
  }}
/>

Image filters

Polotno recognizes two filter categories, each with its own API pattern.

  1. Old filters (use element.set):
sepiaEnabled
grayscaleEnabled
blurEnabled, blurRadius
brightnessEnabled, brightness
  1. Combined filters (use element.setFilter):
cold
natural
warm

temperature
contrast
highlights
shadows
white
black
saturation
vibrance

Examples:

// 1. Old filters
shape.set({ sepiaEnabled: true });
shape.set({ blurEnabled: true, blurRadius: 12 });
shape.set({ brightnessEnabled: true, brightness: 0.25 }); // +25 %

// 2. One‑active preset (replaces previous preset)
shape.setFilter('warm');

// 3. Combined numeric filters (stackable)
shape.setFilter('temperature', -0.2);
shape.setFilter('contrast', 0.15);
shape.setFilter('vibrance', 0.3);

// disabling:
// Old filters off
shape.set({
  sepiaEnabled: false,
  blurEnabled: false,
  brightnessEnabled: false,
});

// Remove current preset
shape.setFilter('warm', null);

// Clear all combined filters
['temperature', 'contrast', 'highlights', 'shadows', 'white', 'black', 'saturation', 'vibrance']
  .forEach((f) => shape.setFilter(f, null));

SVG element

SVG elements work similarly to Image elements but can replace internal colors.

const svgElement = page.addElement({
  type: 'svg',
  src: 'https://example.com/image.svg',
  maskSrc: '', // should we draw mask image over svg element?
  keepRatio: false, // can we change aspect ratio of svg?
  stretchEnabled: false, // can we stretch image on any axis
  x: 0,
  y: 0,
  rotation: 0,
  locked: false, // deprecated
  blurEnabled: false,
  blurRadius: 10,
  brightnessEnabled: false,
  brightness: 0,
  shadowEnabled: false,
  shadowBlur: 5,
  shadowOffsetX: 0,
  shadowOffsetY: 0,
  shadowColor: 'black',
  shadowOpacity: 1,
  name: '', // name of element, can be used to find element in the store
  width: 100,
  height: 100,
  flipX: false,
  flipY: false,
  cornerRadius: 0,
  // can user select element?
  // if false, element will be "invisible" for user clicks
  selectable: true,
  // use for absolute positing of element
  alwaysOnTop: false,
  // also we can hide some elements from the export
  showInExport: true,
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,
  // can we remove element from UI with button or keyboard?
  removable: true,
  // can we resize element?
  resizable: true,
  // map of originalColor -> newColor, used to replace colors in svg image
  // do not change it manually. Instead use `el.replaceColor(originalColor, newColor)`
  colorsReplace: {},
});

If you want to detect colors in an SVG string you can use this:

import { urlToString, getColors, useSvgColors } from 'polotno/utils/svg';

// in react component:
const Toolbar = ({ element }) => {
  const colors = useSvgColors(element.src); // will return array of colors detected in the svg image
};

// in functions:
async function getSvgColors(element) {
  const svgString = await urlToString(element.src);
  const colors = getColors(svgString);
}

svgElement.replaceColor(oldColor, newColor)

Some SVG files support color replacement when a color is defined as fill on internal nodes. You can replace specific colors to modify the original image.

svgElement.replaceColor('red', 'blue');

Line element

Use line elements to draw lines and arrows on the canvas. For now, line elements may not support all available filters from JSON.

const lineElement = page.addElement({
  type: 'line',
  x: 0,
  y: 0,
  width: 400,
  height: 10,
  name: '', // name of element, can be used to find element in the store
  color: 'black',
  rotation: 0,
  dash: [], // array of numbers, like [5, 5]
  startHead: '', // can be empty, arrow, triangle, circle, square, bar
  endHead: '', // can be empty, arrow, triangle, circle, square, bar
  // can user select element?
  // if false, element will be "invisible" for user clicks
  selectable: true,
  // use for absolute positing of element
  alwaysOnTop: false,
  // also we can hide some elements from the export
  showInExport: true,
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,
  // can we remove element from UI with button or keyboard?
  removable: true,
  // can we resize element?
  resizable: true,
  styleEditable: true,
});

Figure element

Use figure to draw basic shapes on the canvas. It has a large collection of shapes controlled by subType.

const figureElement = page.addElement({
  type: 'figure',
  subType: 'rect',
  x: 0,
  y: 0,
  width: 400,
  height: 400,
  fill: 'black',
  stroke: 'red',
  strokeWidth: 40,
  cornerRadius: 40,
});

Currently supported list of subType:

rect, circle, star, triangle, rightTriangle, diamond, pentagon, hexagon, speechBubble, cross, arc, cloud, rightArrow, leftArrow, downArrow, upArrow, asterisk1, asterisk2, bookmark, butterfly, cylinder, diamond2, door, drop1, drop2, explosion, flag, flower, frame, heart1, home, home2, hourglass, house, keyhole, kiss, leaf, lightning1, lightning2, magnet, mithosis, orangeRicky, party, pillow, polygon, rainbow, rhodeIsland, shell, shield1, shield2, skewedRectangle, softFlower, softStar, stairs1, stairs2, teewee, blob1, blob10, blob11, blob12, blob13, blob14, blob15, blob16, blob17, blob18, blob19, blob2, blob20, blob21, blob22, blob23, blob24, blob25, blob26, blob27, blob28, blob29, blob3, blob30, blob31, blob32, blob4, blob5, blob6, blob7, blob8, blob9

Video element

Use video to render a video on the canvas. Video element has many properties similar to the image element.

const videoElement = page.addElement({
  type: 'video',
  x: 0,
  y: 0,
  rotation: 0,

  // url path to video
  src: 'https://example.com/image.png',
  // start/end time of video in % from video duration
  // can be used for trimming video
  startTime: 0,
  endTime: 1,

  shadowEnabled: false,
  shadowBlur: 5,
  shadowOffsetX: 0,
  shadowOffsetY: 0,
  shadowColor: 'black',
  shadowOpacity: 1,
  name: '', // name of element, can be used to find element in the store

  width: 100,
  height: 100,
  cropX: 0, // 0-1 : % from original image width
  cropY: 0, // 0-1 : % from original image height
  cropWidth: 1, // 0-1 : % from original image width
  cropHeight: 1, // 0-1 : % from original image height
  borderColor: 'black',
  borderSize: 0,
  flipX: false,
  flipY: false,

  // can user select element?
  // if false, element will be "invisible" for user clicks
  selectable: true,
  // use for absolute positing of element
  alwaysOnTop: false,
  // also we can hide some elements from the export
  showInExport: true,
  // can element be moved and rotated
  draggable: true,
  // can we change content of element?
  contentEditable: true,

  // can we remove element from UI with button or keyboard?
  removable: true,
  // can we resize element?
  resizable: true,
});

Group element

Group element is a container for other elements. It can be used to move multiple elements together.

Here is the example of default properties and usage:

const page = store.addPage();
page.addElement({
  type: 'text',
  text: 'Hello world',
  id: 'text-1',
});
page.addElement({
  type: 'text',
  text: 'Hello world',
  id: 'text-2',
});
const group = store.groupElements(['text-1', 'text-2']);

group.set({
  name: 'group',
  opacity: 0.5,

  custom: {},

  visible: true,
  selectable: true,
  removable: true,
  alwaysOnTop: false,
  showInExport: true,
});

// ungroup:
store.ungroupElements([group.id]);