← Chrome 148 reference

v148 · origin trial · experimental

HTML-in-canvas

An experimental API that lets you draw live DOM elements — complete with interaction, accessibility, and browser-native styling — directly into a 2D canvas, WebGL texture, or WebGPU texture. Bridges the long-standing gap between the DOM's rich UI semantics and the canvas/WebGL performance model.

Origin Trial — Chrome 148–151 This API is in origin trial. Enable it for your users by registering for the origin trial token, or test locally via chrome://flags/#canvas-draw-element in Chrome 148+. The API shape may change before it ships.

at a glance

Origin trialChrome 148 – 151
ChromeStatus5172548013916160 — HTML-in-canvas
Spec / ExplainerWICG/html-in-canvas GitHub repository
Source: chromestatus and WICG/html-in-canvas, May 2026.

why it exists

WebGL and canvas-based applications (games, design tools, video editors) have always faced a painful choice: use canvas for performance but lose DOM features (accessibility, forms, native controls, CSS styling), or overlay DOM elements on top of the canvas and manage two separate coordinate systems. HTML-in-canvas collapses that into one: nest HTML inside a <canvas>, then draw it directly into the rendering pipeline — with keyboard navigation and screen reader support preserved.

Source: Chrome for Developers — HTML-in-Canvas origin trial blog post, May 2026.

three new primitives

PrimitiveWhat it does
layoutsubtree attribute on <canvas> Opts the canvas into HTML-in-canvas mode. Child DOM elements are laid out and made accessible but not visually rendered by the browser — the canvas draws them instead.
ctx.drawElementImage(element, x, y) 2D canvas: draws the element at the given position; returns a DOMMatrix to sync the element's style.transform with its drawn location so DOM events remain aligned.
gl.texElementImage2D(…, element) / device.copyElementImageToTexture(element, …) WebGL / WebGPU: uploads the element as a texture, enabling it to be used in shaders.
canvas.onpaint event Fires whenever the nested HTML needs to be redrawn (DOM mutation, CSS change, user interaction). The handler redraws the element into the canvas.
Source: WICG/html-in-canvas explainer, May 2026.

example — 2D canvas with form elements

<canvas id="c" style="width:400px;height:300px" layoutsubtree>
  <div id="hud">
    <label for="name">Player name:</label>
    <input id="name" type="text">
  </div>
</canvas>

<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const hud = document.getElementById('hud');

canvas.onpaint = () => {
  ctx.reset();
  // Draw the HUD into the canvas; get back the transform for hit-testing
  const t = ctx.drawElementImage(hud, 10, 10);
  // Sync the DOM position so clicks reach the correct element
  hud.style.transform = t.toString();
};
</script>
Source: WICG/html-in-canvas explainer and Chrome for Developers blog, May 2026.

example — WebGL texture

// Assumes canvas has layoutsubtree and contains an element with id="ui"
canvas.onpaint = () => {
  const uiElement = document.getElementById('ui');
  gl.bindTexture(gl.TEXTURE_2D, uiTexture);
  gl.texElementImage2D(
    gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
    uiElement
  );
  renderScene(); // draw the texture on a quad in 3D space
};
Source: WICG/html-in-canvas explainer, May 2026.

see also