Editing

Keyboard and mouse

Try it in the demo →

Text boxes respond to the keys and gestures people already know from word processors: typing, moving the cursor, selecting with the mouse or Shift, copy and paste, undo and the right-click menu. All of these work with no code once you call enableRichText or createCanvasRichText. This page lists every key and gesture, says which keys the library leaves to your app, and shows the commands that do the same from your own buttons and menus.

Start and stop editing

A box is first selected, then edited:

  1. Click a box to select it. On Konva your app selects it, by putting it on your Konva.Transformer. On a plain canvas the built-in object controls select it (or your app calls rt.select(box) when objectControls is off).
  2. Click the selected box again to place the cursor and type.

Editing ends when someone presses Esc (the box stays selected), presses anywhere outside the box being edited, or starts resizing the box with a handle. Clicks on your page outside the canvas, such as on your toolbar, do not end editing.

From your code:

// Konva
rt.manager.edit(box);      // start editing the box now, as a click on the selected box would
rt.manager.stopEditing();  // stop editing; the box stays selected
rt.manager.editing();      // the box being edited, or null
isEditingText();           // is any box on the page being edited?
stopEditingText();         // stop editing wherever it is on the page

// Plain canvas
rt.stopEditing();
rt.editing();

isEditingText and stopEditingText are exported from @mycreativeshop/rich-text/konva. A box marked editable: false never starts editing; see the read-only boxes section of Getting started.

Keys

Keys reach the text only while a box is being edited. "Ctrl" means Ctrl or Cmd: both work on every system.

Typing

Key What it does
Any character Types it, in the style of the letter before the cursor, or of the first selected letter
Enter Starts a new paragraph in the same style. In an empty list item, Enter ends the list
Shift+Enter A line break inside the paragraph
Tab Types a tab: the text after it moves to the paragraph's next tab stop (see Tab stops)
Backspace, Delete Deletes the letter before or after the cursor, or the selection

Moving and selecting

Key What it does
Left, Right Moves the cursor one letter; with Shift, extends the selection
Up, Down Moves the cursor one line; with Shift, extends the selection
Home, End Moves the cursor to the start or end of the line; with Shift, extends the selection
Ctrl+Home, Ctrl+End Moves the cursor to the start or end of the text; with Shift, extends the selection
Ctrl+A Selects all of the box's text
Esc Stops editing; the box stays selected

Clipboard and undo

Key What it does
Ctrl+C, Ctrl+X Copies or cuts the selection, with its styles
Ctrl+V Pastes at the cursor, replacing the selection
Ctrl+Z Undo
Ctrl+Shift+Z, Ctrl+Y Redo
Ctrl+B, Ctrl+I, Ctrl+U Left to your app (see below)

Mouse and touch

Gesture What it does
Click Selects a box; a click on the selected box places the cursor
Drag across text Selects text in the box being edited, also past the box's edge
Drag a box Moves it: on Konva when the box is draggable, on a plain canvas with the object controls. A box being edited does not move
Double-click On the selected box or the box being edited, selects the word under the pointer
Shift+click Extends the selection to the click
Right-click Opens the menu: spelling suggestions, Cut, Copy and Paste
Side handles Change the width; the text wraps again (see Resize handles)
Corner handles Scale the text

On touch screens a tap is a click, and a double-tap selects a word. The library allows a little more movement and time for a touch than for a mouse before a tap counts as a drag or two taps stop counting as a double-tap.

Bold, italic and underline keys

The library does not bind Ctrl+B, Ctrl+I or Ctrl+U, because what they do belongs to your app's toolbar. While a box is being edited, a Ctrl+letter key the library does not use never types its letter, and the key goes on to your page. Bind the keys yourself:

window.addEventListener("keydown", (e) => {
  if (!(e.ctrlKey || e.metaKey) || e.altKey) return;
  const commands = rt.manager; // plain canvas: rt
  if (!commands.selected()) return; // no box selected: the key is the browser's
  const key = e.key.toLowerCase();
  if (key === "b") commands.toggleBold();
  else if (key === "i") commands.toggleItalic();
  else if (key === "u") commands.toggleUnderline();
  else return;
  e.preventDefault(); // some browsers open bookmarks or the page source on these keys
});

The commands change the selected words while a box is being edited, and the whole box when it is only selected. Ctrl with Alt is left as typing, so the characters that European keyboards type with AltGr (such as @, € and {) still type.

Copy, cut and paste

Copy and cut put the selected text on the system clipboard as plain text, and keep its styles inside the library. A paste of text copied from a text box puts back each letter's style, including line breaks between paragraphs. Text pasted from anywhere else (another app, a web page, Word) arrives as plain text in the style of the cursor's position; each line break in it starts a new paragraph.

The same commands are available for your own menu or buttons:

// Konva
rt.manager.copy();          // false when nothing is selected
rt.manager.cut();
await rt.manager.paste();
rt.manager.hasSelection();  // whether Copy and Cut can do anything

// Plain canvas
rt.copy();
rt.cut();
await rt.paste();           // false when no box is being edited
rt.hasSelection();

Call paste() from a click: browsers let a page read the clipboard only during a user action, and some ask the user first. On Konva, onClipboardAccessDenied tells you when the browser refused, so you can suggest Ctrl+V, which always works:

const rt = enableRichText(stage, {
  onClipboardAccessDenied: () => showMessage("Press Ctrl+V to paste."),
});

Undo and redo

Ctrl+Z undoes and Ctrl+Shift+Z or Ctrl+Y redoes while a box is being edited. Letters typed in one burst are one step: a space, a tab, moving the cursor or a pause of one second starts the next step, so undo takes back about a word at a time. A paste and a resize are each one step. Formatting commands on the same box less than a second apart join one step, so dragging a size slider is undone in one press. The library keeps the last 50 steps.

Undo and redo never start or stop editing: in the box being edited the cursor goes back to where the change was, and a box that is not being edited is selected and shows no cursor.

From your own buttons:

rt.manager.undo(); // plain canvas: rt.undo()
rt.manager.redo(); // plain canvas: rt.redo()

On Konva, disableInternalUndoRedoShortcuts: true makes the library ignore Ctrl+Z and Ctrl+Y so your app can bind them and call undo() and redo() itself. To keep text changes in your app's own undo history beside its other changes, use "host" history mode, described in Your app's undo.

The right-click menu

A right-click on the box being edited opens the library's menu: up to five spelling suggestions, Add to dictionary and Ignore on a misspelled word (see Spellcheck), then Cut and Copy when text is selected, and Paste. A right-click anywhere else is left to your app.

On Konva the menu works with no code. On a plain canvas, forward the browser's contextmenu event:

canvas.addEventListener("contextmenu", (e) => {
  if (rt.contextMenu(rt.fromEvent(e, canvas, sceneToCanvas), { x: e.clientX, y: e.clientY }).handled) e.preventDefault();
});

To show your own menu instead, pass enableContextMenu: false to enableRichText or createCanvasRichText.

Keys the library leaves to your page

  • Every key while no box is being edited. Your own shortcuts, such as Delete to remove a selected box, should check isEditingText() (plain canvas: rt.editing()) first; see Your shortcuts and editing events.
  • Every key while the page's focus is in an input, textarea, select or contenteditable element.
  • Shift+Tab, and Tab with Ctrl, Cmd or Alt. After Esc ends editing, Tab moves through the page as usual, so the keyboard is never trapped in a text box.
  • Ctrl+letter keys the library does not use, such as Ctrl+B, Ctrl+S and Ctrl+P.

The library listens for keys on the window. To take a key before the library does, for example to give Tab another job while editing, listen on the document in the capture phase:

document.addEventListener("keydown", (e) => {
  if (e.key === "Tab" && isEditingText()) {
    e.preventDefault();
    e.stopPropagation(); // the library never sees this Tab
    moveToNextField();
  }
}, true);

Options

Option Surface Default What it does
enableContextMenu both true Shows the library's right-click menu on the box being edited
enableSpellcheck both true Underlines misspelled words while editing (see Spellcheck)
objectControls plain canvas true Click selects, drag moves, handles resize; false leaves these to your app
selectionColor plain canvas translucent blue The color of the text selection
caretWidth plain canvas 1.5 The cursor's width in CSS pixels
disableInternalUndoRedoShortcuts Konva false Leaves Ctrl+Z and Ctrl+Y to your app
onClipboardAccessDenied Konva none Called when the browser refused to let a paste read the clipboard
onBeforeMouseDown Konva none Called before a press on a box reaches the library; return true to keep the library from handling it

Limits

Limit: Ctrl+Left and Ctrl+Right move one letter, not one word, and Ctrl+Backspace deletes one letter. Page Up and Page Down do nothing in a text box.

Limit: There is no triple-click: a third click places the cursor.

Limit: On Konva, the cursor and selection are drawn on the box's layer each time the layer draws. A layer set to clearBeforeDraw(false) keeps every cursor it has drawn, so a blinking or moving cursor leaves marks. Keep text boxes you edit on a layer that clears.

Limit: Only a physical keyboard types into a text box. Phone keyboards, input methods for Chinese, Japanese and Korean, accent keys, dictation and autocorrect work in Story Mode today; see Coming soon.

In the API reference