How to show rich html on canvas with Konva


How to show complex styles (like bold) and enable rich text editing features?

Canvas’s text API is very limited. Konva.Text allows you to add many different styles, support multiline text, etc. But at the current moment it has limitations. You can’t use different styles for different parts of Konva.Text. For that case you have to use several Konva.Text instances.

If you want show complex styles on canvas we can do a hacky workaround. The idea is simple:

  1. Create DOM element and put styled text in it
  2. Convert DOM element into image with html2canvas.
  3. Use that image for Konva.Image.

Instructions: try to type a text into the editor

Konva Rich Text Demoview raw
<!DOCTYPE html>
<script src=""></script>
<script src=""></script>

<script src=""></script>
<meta charset="utf-8" />
<title>Konva Rich text on Canvas Demo</title>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;

#editor-container {
height: 80px;

<div id="editor-container">
That is <u>some</u> <span style="color: red"> styled text</span> on
<h2>What do you think about it?</h2>
Rendered stage:
<div id="container"></div>
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'

var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
container: 'container',
width: width,
height: height

const layer = new Konva.Layer();

const shape = new Konva.Image({
x: 10,
y: 10,
draggable: true,
stroke: 'red',
scaleX: 1 / window.devicePixelRatio,
scaleY: 1 / window.devicePixelRatio


function renderText() {
// convert DOM into image
html2canvas(document.querySelector('.ql-editor'), {
backgroundColor: 'rgba(0,0,0,0)'
}).then(canvas => {
// show it inside Konva.Image

// batch updates, so we don't render text too frequently
var timeout = null;
function requestTextUpdate() {
if (timeout) {
timeout = setTimeout(function() {
timeout = null;
}, 500);

// render text on all changes
quill.on('text-change', requestTextUpdate);
// make initial rendering