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.
chrome://flags/#canvas-draw-element in Chrome 148+. The API shape may change before it ships.
at a glance
| Origin trial | Chrome 148 – 151 |
|---|---|
| ChromeStatus | 5172548013916160 — HTML-in-canvas |
| Spec / Explainer | WICG/html-in-canvas GitHub repository |
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.
three new primitives
| Primitive | What 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. |
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.