A list item is a paragraph with a marker in front of it. The marker can be a bullet, a number, any character such as a symbol, a letter or an emoji, or a vector shape with a mark inside it, such as a white check in a colored circle. Lists are for menus, feature lists and steps, and people edit them with the keys they already know.
Make a list
// Konva: const rt = enableRichText(stage)
rt.manager.toggleBulletList(); // bullets, with the default "disc" marker
rt.manager.toggleBulletList("★"); // bullets, with a star
// Plain canvas: const rt = createCanvasRichText({ onChange: render })
rt.toggleBulletList();
toggleBulletList turns the paragraphs it reaches into list items, or back into plain paragraphs. If any of them is
not a list item yet, all of them become list items, and the ones that were list items already keep their marker. If
all of them are list items, all of them become plain paragraphs, and their marker, indent and marker offset are removed.
It reaches paragraphs the same way the paragraph commands do: every paragraph of a box that is only selected, every
paragraph the selection touches while editing, or the paragraph the cursor is in. To change boxes you name instead,
pass them as the optional last argument. With no marker to give, pass undefined first:
rt.manager.toggleBulletList(undefined, [specials]);
Each call is one undo step.
Change the marker
rt.manager.setBulletStyle("decimal"); // 1. 2. 3.
rt.manager.setBulletStyle("🍋"); // an emoji, drawn in color
setBulletStyle changes the marker of the list items it reaches and leaves plain paragraphs as they are. The marker is
one of these:
| Marker | Draws |
|---|---|
"disc" |
• (the default) |
"circle" |
◦ |
"square" |
▪ |
"decimal" |
1. 2. 3. |
| Any character | That character: "–", "➤", "★", "✓", a letter, or an emoji |
Numbers count the list items that follow one another: a plain paragraph, or an item with a different marker, between two numbered items starts the count again at 1.
A character marker is drawn in the font, size and color of its item's first letter, at the regular weight. Under a gradient or image fill, a character marker takes the fill as the letters do.
Limit: A marker is one character. A string longer than three UTF-16 code units, such as some emoji made of several joined emoji, draws a disc instead.
A shape with a mark inside
A vector marker is drawn from two shapes, each in its own color: a backing shape and a mark on top of it. Set it as
marker in each list item's blockAttributes, then apply the document with setDocument, which is one undo step:
// A check mark in a 24x24 box (SVG path data)
const CHECK = "M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z";
const doc = structuredClone(box.getDocument()); // never change the live document in place
for (const block of doc.blocks) {
if (block.type === "list-item") {
block.blockAttributes.marker = { shape: "circle", shapeFill: "#5E2DC1", glyphPath: CHECK, glyphColor: "#FFFFFF" };
}
}
rt.manager.setDocument(doc, [box]); // plain canvas: rt.setDocument(doc, [box])
| Field | What it does |
|---|---|
shape |
The backing shape: "circle", "square" (a square with rounded corners), or "none" (the default) for the mark alone. |
shapeFill |
The backing shape's color, any CSS color. Default: the item's text color. |
glyphPath |
The mark, as SVG path data in a 24x24 box. The path is filled, not stroked. On a backing shape the mark takes 60% of the marker's size. Leave it out for a shape with no mark. |
glyphColor |
The mark's color. Default: the item's text color. |
scale |
The marker's size, as a multiple of the item's font size. Default 1. |
A vector marker is centered in the space before the item's text, at the middle of the capital letters' height. It keeps
its own colors under a gradient or image fill. setBulletStyle replaces a vector marker with the character you give
it.
Indent
Two list settings in blockAttributes place the marker and the text, both as multiples of the item's font size:
| Field | What it does |
|---|---|
listIndent |
Where the item's text starts, from the left edge of the box. Default 2. Every line of the item starts there, so wrapped lines line up with the first. |
bulletOffset |
Where the marker's space starts, from the left edge of the box. Default 0.6. The marker is centered between this and listIndent. |
There is no command for these two settings: set them in the document and apply it with setDocument, as for a vector
marker. Because they are multiples of the font size, the indent grows and shrinks with the text.
Typing in a list
While a list item is being edited:
- Enter starts a new list item with the same marker and settings.
- Enter on an empty list item turns that item into a plain paragraph, which ends the list.
- Enter at the start of an item leaves an empty item above it.
- Shift+Enter breaks the line inside the item. The new line starts at the item's text indent and gets no marker.
- Tab types a tab, which moves the text after it to the next tab stop. It does not indent the item: see Tab stops.
Limit: Lists have one level. There is no nesting; to indent a whole list further, raise its
listIndentandbulletOffset.
Show the current list
FormattingState reports isList (the paragraph at the cursor is a list item) and listStyle
(its marker), so a toolbar can light the right marker button.
In the API reference
- TextFormatting:
toggleBulletList,setBulletStyle,setDocument - ListMarker: the vector marker's fields
- BlockAttributes:
listStyle,listIndent,bulletOffset,marker - FormattingState