HTML-in-Canvas in Chrome 157: Interactive DOM inside 2D, WebGL, and WebGPU

Published: October 26, 2026

Following a successful origin trial, Chrome 157 marks the official stable release of the HTML-in-Canvas API. The HTML-in-Canvas API bridges the gap between the interactive, accessible world of the DOM and the high-performance, pixel-level control of <canvas>. This API gives you the best of both worlds—rich browser capabilities and GPU-accelerated canvas graphics.

Video overview of the HTML-in-Canvas API.

The canvas versus DOM dilemma

Previously, when creating visually demanding web apps, you had to choose between standard HTML elements and raw canvas contexts.

Technology Strengths Limitations
<canvas> Low-level pixel control with GPU access to drive 2D and 3D graphics pipelines, custom shaders, and offscreen workers. High-performance rendering for heavy, data-dense UIs. No built-in web platform features such as text selection, copy and paste, right-click actions, and text wrapping. The opaque pixel grid doesn't support screen readers, Find-in-Page, auto-translate, or autofill by default, and requires a fallback implementation.
HTML Semantic UI out of the box with built-in form controls, responsive typography, and CSS styling. Deep browser integration for screen readers, Find-in-Page, and DevTools. Limited ability to control performance for complex UIs. Visual effects are restricted to standard CSS and SVG without direct pixel manipulation or shaders.

Before HTML-in-Canvas

Before this API, if you built canvas-heavy UIs, you had to choose between two approaches, each with its own downsides:

  1. Rendering text directly as canvas pixels (fillText()): Apps drew text and UI controls imperatively as raw pixels. This approach resulted in the following downsides:
    • Accessibility breakdown: Screen readers and assistive tools can't read canvas pixels unless you manually construct and sync an invisible fallback DOM.
    • Loss of browser features: Users can't search with Find-in-Page (Ctrl/Cmd+F), copy and paste text naturally, trigger context menus, or use browser translation and spellcheck.
    • Complex typography engines: Supporting internationalization requires bundling large JavaScript layout engines.
  2. Floating HTML overlays on top of the canvas: For example, using libraries that position standard HTML elements over the canvas by calculating bounding boxes and matrix transforms in JavaScript. The downsides of this approach include:
    • Synchronization lag and visual tearing: Scrolling, zooming, or camera movements in 3D can cause the overlay DOM elements to drift or jitter relative to the canvas pixels due to frame-timing differences.
    • Clipping and z-ordering limitations: HTML overlays always sit on top of the entire canvas buffer. Embedding HTML inside a 3D scene (for example, behind a 3D object, inside a glass material, or reflected in a mirror) wasn't possible without complex iframe-to-image workarounds.
    • Performance overhead: To keep overlays aligned with the canvas, you have to recalculate each overlay's transform in JavaScript and write it to style.transform on every frame. The browser then parses each string and recalculates the element's style before it can render the frame, so main-thread work grows with every overlay that you add. In a 2D context, drawElementImage() updates the element's position for you. In WebGL and WebGPU, you pass the transform that you calculate to updateElementGeometry() as a matrix. Either way, the browser doesn't parse CSS or recalculate styles.

Key benefits of HTML-in-Canvas

HTML-in-Canvas eliminates these trade-offs. By placing HTML inside the <canvas> element, the content remains interactive, and all browser integrations function automatically.

HTML content rendered inside a <canvas> has the same capabilities of HTML outside of <canvas>:

  • Text layout and formatting: support for text layout and formatting, including multiline or bidirectional text with CSS styles applied.
  • Form controls: expressive form controls with extensive CSS and shader customization options.
  • Text selection, copy and paste, and right-click: Users can highlight text inside 3D scenes or trigger context menus.
  • Accessibility: HTML content rendered inside the canvas is exposed to the accessibility tree for screen readers.
  • Browser features integration: Browser features such as translate, autofill, and Find-in-Page work out of the box. Users can translate or search for text inside WebGL and WebGPU textures.
  • Extension integration: Browser extensions work on the content. For example, a text-replacement extension automatically updates the text rendered on your 3D meshes.
  • DevTools integration: Inspect and tweak CSS styles for canvas UI elements directly in Chrome DevTools.
  • Indexability and AI agents: Web crawlers and AI agents can index DOM content rendered into 2D and 3D scenes.
  • Media editing and export: Export full canvas composites containing live DOM elements directly to images (toDataURL(), toBlob()) or video streams (captureStream()).
Demo comparing feature integration of text rendered directly into a canvas and HTML-in-Canvas. In the HTML-in-Canvas pane, the content is selectable and translatable, and browser features such as autofill work out of the box. In the standard canvas pane, the content is rendered directly into a canvas using the fillText method and isn't interactive.

Primary use cases

HTML-in-Canvas unlocks capabilities across several areas:

  • Large canvas-based apps: Heavyweight web apps can render UI components directly into canvas workspaces, improving accessibility and reducing bundle size.
  • 3D scenes and games: Immersive WebXR experiences and games can position interactive DOM elements—such as in-game terminals or readable 3D books—directly inside scenes.
  • Media editing and export: Creative tools combining rich HTML typography with shader effects can export composite scenes directly into images or video streams.
  • Expressive UIs: You can manipulate HTML content as raw pixels to build shader-driven visual effects.

HTML-in-Canvas quickstart

Rendering HTML in a canvas requires the following steps:

  1. Prepare your canvas. Declaratively set the right attributes to let the browser know it should render HTML into a canvas. This setup is identical across 2D, WebGL, and WebGPU contexts. Learn how to set your canvas up and how to declare HTML elements to be drawn independently.

    <!-- Prepare your canvas by setting the `content` attribute -->
    <canvas id="canvas" width="600" height="400" content="drawable">
      <!-- Mark child as `drawable` to render to canvas -->
      <div id="myElement" drawable>
        <!-- Your HTML here -->
      </div>
    </canvas>
    
  2. Draw the element image into the canvas. The exact implementation depends on whether you render HTML in a 2D, WebGL, or WebGPU context.

    const ctx = canvas.getContext("2d");
    // Draw HTML element into canvas in 2D
    ctx.drawElementImage(myElement, myElementX, myElementY);
    
  3. Optional: Synchronize the DOM and the pixels. Geometry synchronization also depends on the context you use. In 2D, the browser handles it automatically by default, while in 3D contexts you need to construct a transform and pass it to the updateElementGeometry method.

    // In 3D, construct a transform as needed, for example:
    const transform = new DOMMatrix().translate(x, y);
    // Synchronize the element's DOM and pixels
    canvas.updateElementGeometry(myElement, { canvasTransform: transform });
    

Framework and ecosystem support

Major WebGL and 3D graphics libraries support HTML-in-Canvas:

  • Three.js: offers experimental support using THREE.HTMLTexture.

    const material = new THREE.MeshBasicMaterial();
    material.map = new THREE.HTMLTexture(uiElement);
    const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material);
    scene.add(mesh);
    
  • PlayCanvas: supports HTML texture streaming using setSource().

    canvas.addEventListener('paint', () => {
      htmlTexture.setSource(htmlElement);
    }, { once: true });
    
  • Babylon.js: provides built-in binding through BABYLON.HtmlTexture.

    const htmlTexture = new BABYLON.HtmlTexture("htmlTexture", uiElement, scene);
    material.diffuseTexture = htmlTexture;
    
  • PixiJS: shipped built-in support in version v8.19.0 with HTMLSource.

    import { HTMLSource } from 'pixi.js/html-source';
    const sprite = Sprite.from(new HTMLSource({ resource: form, autoUpdate: true }));
    app.stage.addChild(sprite);
    
  • CanvasUI: an open-source component library designed specifically for HTML-in-Canvas.

For more implementation details, check each framework's documentation.

Feature detection and fallback strategies

To ensure cross-browser compatibility, verify API support before running your code:

export function supportsHtmlInCanvas() {
  if (typeof document === "undefined") return false;
  const canvas = document.createElement("canvas");
  canvas.setAttribute("content", "drawable");
  return canvas.content === "drawable";
}

If the API is unavailable, you can fall back to alternative UIs, floating HTML overlays, or one of the available libraries (for example, three-html-render, html2canvas, or dom-to-image).

Next steps