Text formatting

Character styles

Try it in the demo →

Character styles are the font family, size, weight, bold, italic, underline, strikethrough and color of the letters. Your toolbar sets them with one command each. A command changes a whole text box when the box is only selected, or the selected words while someone is editing the box, so a headline can have one word in another color or weight.

Call the commands

On Konva the commands are on the manager that enableRichText returns. On a plain canvas they are on the object that createCanvasRichText returns. The names and arguments are the same.

// Konva
const rt = enableRichText(stage);
rt.manager.toggleBold();
rt.manager.setColor("#5E2DC1");

// Plain canvas
const rt = createCanvasRichText({ onChange: render });
rt.toggleBold();
rt.setColor("#5E2DC1");

The rest of this page shows the Konva calls. On a plain canvas, call the same commands on rt.

What a command changes

  • A selected box that is not being edited: all of its text.
  • A box being edited, with words selected: the selected words.
  • A box being edited, with only the cursor: the whole paragraph the cursor is in. There is no style waiting for the next letters typed: new letters take the style of the letter before the cursor.
  • Boxes you name: every command takes an optional last argument, a list of boxes. The command then changes those boxes instead of the selection. A box in the list that is being edited still changes only its selected words.
rt.manager.setColor("#FF7903", [headline, footer]);

Each command is one undo step, and a command on several boxes is one undo step for all of them. A paragraph whose letters are all changed also takes the new family, size, weight or color as its own, so text typed later in it, and an empty line in it, use that style.

Font family

await rt.manager.setFontFamily("Lora");

setFontFamily returns a promise. The library loads the family's regular, bold, italic and bold italic faces first, then changes the text and lays it out in the new font. Until then the box keeps showing its current font, never a blank box. Bold, italic and the weight already set are kept. On several boxes, every box's font loads first and then all of them change together, as one undo step.

Every Google Fonts family works by name. For your own fonts, pass their address as the third argument, after the boxes (null for the current box):

await rt.manager.setFontFamily("Acme Sans", null, {
  fontFaceUrl: "https://cdn.example.com/acme-sans.css", // a stylesheet with the family's @font-face rules
  fontImageUrl: "https://cdn.example.com/acme-sans.png", // a preview image for your font picker
  description: "Rounded sans for headlines",
  attribution: "Acme Type Foundry",
});
Option What it does
fontFaceUrl The address of a stylesheet with the family's @font-face rules. The library loads the font from it and saves the address in the document, so the design opens anywhere without your fonts lookup.
fontImageUrl The address of a preview image of the font. Saved with the font; never drawn.
description A short description of the font. Saved with the font; never drawn.
attribution The font's author or license credit. Saved with the font; never drawn.

The three descriptive fields are saved only for a custom font: one given a fontFaceUrl, or one your fonts lookup knows. A family your lookup knows needs no options at all, and its address is saved the same way. The plain canvas takes the same options: rt.setFontFamily(family, null, options). Both ways are described in Fonts.

Font size

rt.manager.setFontSize(48); // every changed letter is 48 pixels
rt.manager.scaleFontSize(1.15); // every size 15% larger, in proportion

setFontSize gives every changed letter one size, in pixels. scaleFontSize multiplies each letter's own size by a factor, so mixed sizes keep their proportions. In "Saturday, 10am - 4pm" with "Saturday" larger, scaling by 1.15 makes both parts larger and "Saturday" stays the larger word. Outline widths scale with the letters, and so does the letter spacing of every paragraph changed whole. Line height and paragraph spacing are multiples of the font size, so they follow on their own. A factor of 1, zero, a negative number or NaN changes nothing.

On a box that is not being edited, scaleFontSize scales the whole box: every size, the letter spacing, the outlines, paragraph borders and the drop shadow.

Tip: Inside a scaled Konva group, sizes, outline widths and letter spacing are read and set as they look on screen. A size read from the toolbar state, changed and written back moves by exactly the change.

Font weight

rt.manager.setFontWeight(600); // 100 to 900

The weight is a number from 100 to 900, and it decides which face is drawn. Setting it also sets bold to match: bold is on at 700 and above. A weight the family doesn't have is drawn with the nearest weight the family has, as the browser would pick it. The document keeps the weight you set: move the text to a family that has that weight and it is drawn at that weight. When you provide your own fonts, list the weights each family ships (weights in your fonts lookup, see Fonts).

Bold, italic, underline and strikethrough

rt.manager.toggleBold();
rt.manager.toggleItalic();
rt.manager.toggleUnderline();
rt.manager.toggleStrikethrough();

Each toggle does what your toolbar shows. If the toolbar state says the text is bold, toggleBold removes bold from all of the changed text; otherwise it makes all of it bold. Bold also sets the weight: 700 on, 400 off.

Color

rt.manager.setColor("#5E2DC1"); // any CSS color: "rgb(94, 45, 193)", "rebeccapurple"

setColor sets a solid color on the letters. A gradient or image fill belongs to the whole box, and setting a color removes it, even when only some words were selected: the letters show their own colors again. See Gradient and image fills.

Outline

rt.manager.setStrokeWidth(2); // pixels; 0 removes the outline
rt.manager.setStrokeColor("#1B1130");

An outline is a character style: it changes the same letters the other commands change. If none of those letters has an outline color yet, setStrokeWidth uses black. Shadows and outlines shows how an outline, a color and a shadow combine into a look.

Show the current style

FormattingState reports the style at the cursor or selection while editing, or of the first letter of a selected box. Its character fields are bold, italic, underline, strikethrough, fontFamily, fontSize, fontWeight (undefined when it can't be read, for example across mixed weights), color, strokeWidth and strokeColor.

defaultRichTextContext.onFormattingChange((state) => {
  boldButton.classList.toggle("active", !!state?.bold);
  sizeInput.value = String(state?.fontSize ?? "");
});
// Plain canvas: rt.onFormattingChange((state) => ...)

Your own toolbar covers keeping a toolbar in step.

In the API reference