React Konva Utilities

raw JSON →
2.0.0 verified Sat Apr 25 auth: no javascript

react-konva-utils is a supplementary library providing useful components and hooks for `react-konva` applications. As of its current stable version 2.0.0, it offers key functionalities such as the `Html` component for seamlessly embedding standard DOM elements within a Konva stage and the `Portal` component for relocating Konva nodes within the stage's rendering hierarchy. This package is designed to simplify complex UI scenarios that require blending canvas-rendered graphics with interactive HTML elements. It maintains compatibility with recent major versions of its peer dependencies, including `react` (v18/v19), `react-dom` (v18/v19), `konva` (v8/v9/v10), and `react-konva` (v18/v19), aligning its release cadence with these core libraries. Its primary differentiation lies in abstracting away the manual DOM manipulation and complex node management often required to achieve advanced canvas-DOM integrations.

error Error: The `parentNodeFunc` prop in `Html` must return a valid DOM node.
cause The `parentNodeFunc` prop provided to the `Html` component returned `null`, `undefined`, or a non-DOM element, preventing the HTML content from being mounted correctly.
fix
Ensure parentNodeFunc always returns a valid DOM element where the HTML content should be appended. The default is stage?.container(), which typically works if the Konva stage is properly initialized.
error TypeError: Cannot read properties of undefined (reading 'x')
cause Attempting to pass Konva-specific props (like `x`, `y`, `draggable`) to a non-Konva component, or passing non-Konva components directly as children to the `Portal` component.
fix
Ensure that children passed to the Portal component are valid react-konva components (e.g., Rect, Circle, Group). Standard HTML elements or non-Konva React components cannot directly receive Konva transformation props.
error Error: The `selector` prop for `Portal` must be a valid CSS selector string for a Konva `Group` or `Layer`.
cause The `selector` prop provided to the `Portal` component does not correspond to an existing `Konva.Group` or `Konva.Layer` element within the Konva stage hierarchy, or targets an invalid Konva node type.
fix
Verify that a Konva.Group or Konva.Layer with the specified name or id (e.g., <Group name='my-target' />) exists within the Konva stage. The selector must target a valid Konva node that can act as a container for other nodes.
gotcha The `Html` component renders standard DOM elements *over* the Konva canvas, not within it. This means any content rendered via `Html` will *not* be included when exporting the canvas to an image (e.g., `stage.toDataURL()`).
fix Design your application such that critical, exportable content is rendered directly with Konva shapes. If HTML content must be included in exports, consider using a separate DOM-to-image library to capture the HTML, or redraw the content using Konva shapes programmatically.
breaking Using `react-konva-utils` with incompatible versions of `konva`, `react`, `react-dom`, or `react-konva` can lead to runtime errors, unexpected rendering, or an inability to use core features. Refer to peer dependency ranges to ensure compatibility.
fix Check your `package.json` for `konva`, `react`, `react-dom`, and `react-konva`. Upgrade or downgrade them to satisfy the ranges specified in `react-konva-utils`'s peer dependencies (e.g., `npm install konva@^10 react@^18 react-dom@^18 react-konva@^19`).
gotcha The `Html` component's `transform` prop (which defaults to `true`) automatically applies Konva's position and scale transformations to the underlying DOM element. If you are also applying CSS transformations or manually positioning the `divProps` container, it can lead to double transformations or misaligned content.
fix If you are manually controlling the position or style of the HTML content via `divProps.style` or external CSS, set `transform={false}` on the `Html` component to prevent automatic Konva transformations from interfering. Only enable `transform` if you want `Html` to automatically follow the Konva stage's transformations.
gotcha Embedding highly dynamic or complex DOM structures within the `Html` component, especially those with frequent updates, can lead to performance degradation. While Konva renders efficiently on the canvas, the `Html` component involves standard DOM manipulation which can be costly for complex or rapidly changing content.
fix Keep `Html` content as simple as possible. For static or infrequently updated content, this is less of an issue. For highly interactive elements, consider if they can be represented as pure Konva shapes or if their updates can be throttled to reduce DOM reflows and repaints.
npm install react-konva-utils
yarn add react-konva-utils
pnpm add react-konva-utils

This quickstart demonstrates how to embed and position standard HTML content directly onto a Konva canvas using the `Html` component. It showcases interactive DOM elements within a canvas scene, allowing for rich UI overlays.

import React from 'react';
import { Stage, Layer, Rect } from 'react-konva';
import { Html } from 'react-konva-utils';

const App = () => {
  const stageWidth = window.innerWidth;
  const stageHeight = window.innerHeight;

  return (
    <Stage width={stageWidth} height={stageHeight}>
      <Layer>
        <Rect x={50} y={50} width={100} height={100} fill="blue" />
        <Html
          transform
          groupProps={{ x: 120, y: 120 }}
          divProps={{
            style: {
              background: 'white',
              padding: '10px',
              border: '2px solid #ccc',
              borderRadius: '5px',
              boxShadow: '0px 2px 5px rgba(0,0,0,0.2)'
            }
          }}
        >
          <div>
            <h3 style={{ margin: '0 0 8px 0', color: '#333' }}>Konva HTML Overlay</h3>
            <p style={{ margin: '0', fontSize: '14px', color: '#555' }}>
              This is a standard DOM element rendered over the canvas.
            </p>
            <button
              onClick={() => alert('Button in HTML clicked!')}
              style={{ marginTop: '10px', padding: '8px 12px', cursor: 'pointer' }}
            >
              Click Me!
            </button>
          </div>
        </Html>
        <Rect x={300} y={250} width={150} height={80} fill="green" />
      </Layer>
    </Stage>
  );
};

export default App;