HTML in Canvas API
An emerging web standard solving a long-standing developer headache: drawing live, interactive HTML elements natively into graphics like 2D Canvas, WebGL, or WebGPU while keeping them accessible.
The Problem It Solves
Imagine you are building a browser-based 3D game using WebGL or a modern interactive canvas app. You want to display an in-game computer screen, or maybe just a settings menu. You quickly hit a wall:
HTML handles text, forms, scrolling, and accessibility perfectly. But you cannot directly draw an HTML <div> onto a <canvas>.
Instead, developers historically had to do one of two things:
- The CSS Overlay Hack: Floating HTML elements on top of the canvas using CSS
position: absolute;. (This doesn't work if the element needs to be inside a 3D world). - Reinventing the Wheel: Writing thousands of lines of complex JavaScript graphics code to manually draw text, fake input cursors, and mimic scrollbars entirely inside the canvas.
The Solution: HTML-in-Canvas
The HTML in Canvas API is an experimental proposal (incubated by the WICG) created exactly for this. It natively acts as a bridge between the DOM and your Graphics.
It allows the browser to take a live, high-fidelity snapshot of HTML elements that are descendants of the canvas and hand them directly to the graphics context as a texture.
Because the HTML elements remain in the DOM tree as actual children of the <canvas>, they remain fully accessible to screen readers, focusable via keyboard, and interactive, even though they are visually rendered inside the canvas buffer.
The Proposed Primitives
The emerging proposal introduces several key primitives to function securely and efficiently:
1. The layoutsubtree Attribute
To opt-in, you add the layoutsubtree attribute to the <canvas> element. This tells the browser that the canvas children should participate in standard layout and hit testing. It creates a stacking context for the children, ensuring they are prepared for capture without being rendered in the normal page flow.
2. The Paint Event & requestPaint()
Instead of manual loops, the API uses a paint event that fires only when the target HTML visually changes. You can also manually trigger a re-render using canvas.requestPaint(), which functions similarly to requestAnimationFrame().
3. Rasterization Methods
The proposed methods allow you to draw the HTML content into different graphics contexts:
- 2D Canvas: Uses
ctx.drawElementImage(element, x, y). - WebGL: Uses
gl.texElementImage2D(...)to turn the element into a 3D texture. - WebGPU: Uses
copyElementImageToTexture().
4. captureElementImage()
For advanced use cases like OffscreenCanvas in web workers, you can capture an ElementImage snapshot. This object can be transferred to a worker thread and drawn independently of the main thread.
Code Example (Proposed Syntax)
This snippet demonstrates the latest proposed syntax. Note how drawElementImage returns a DOMMatrix, which is used to synchronize the element's actual position in the DOM with its visual position in the canvas.
Privacy-Preserving Painting
To prevent security leaks (like cross-origin data theft), the API implements "privacy-preserving painting." When an element is drawn to a canvas, certain sensitive information is automatically excluded:
- Cross-Origin Data: Iframes, images, or CSS
url()references from different origins will not be painted. - User Secrets: Pending form autofill information and spelling/grammar markers are hidden.
- History: Visited link information (which could reveal a user's browsing history) is treated as unvisited.
- Anti-Aliasing: Subpixel text anti-aliasing is disabled to prevent timing attacks that could reveal sensitive pixels.
If this API makes its way out of incubation and into modern browsers, rendering complex components into games, VR headsets, 3D scenes, or static image exports will become a native and blazing-fast part of the web. For reliable updates, follow the official WICG html-in-canvas living explainer.
chrome://flags/#canvas-draw-element.