For over a decade, web developers have faced an uncomfortable trade-off: build with the DOM and get accessibility, layout, and SEO for free — or build with canvas and get pixel-level creative control. Choosing one meant sacrificing the other. That tension is finally dissolving.
The HTML-in-Canvas API, a new WICG proposal currently shipping behind a flag in Chromium 146+, lets you render real, interactive HTML elements directly inside a canvas context. It is, without exaggeration, one of the most consequential browser API proposals in years.
TL;DR
- The HTML-in-Canvas API bridges the long-standing gap between DOM-based layout and canvas-based creative control
- Three core primitives —
layoutsubtree,drawElementImage(), and thepaintevent — make the API surprisingly approachable - Use cases span from post-processing shader effects to 3D UI rendering with Three.js
- Currently experimental in Chromium 146+ behind a flag — not production-ready, but worth prototyping against now
- Teams building creative tools, data visualisation dashboards, or immersive web experiences should start experimenting today
The Problem This Solves
Canvas gives you a blank pixel surface. You can draw anything — shapes, images, video frames, WebGL shaders — but none of it is real HTML. Text inside canvas is not selectable. Forms are not interactive. Screen readers cannot parse it. Search engines cannot index it.
Conversely, the DOM gives you layout, accessibility, CSS styling, and interactivity — but limited creative control. Want to apply a ripple distortion to a signup form? A page-curl transition between views? A frosted glass effect that actually works on live content? You are either reaching for complex CSS hacks, duplicating your UI into an offscreen canvas, or giving up.
The HTML-in-Canvas API eliminates this either-or choice. You write normal HTML, style it with CSS, and then render it as a canvas texture — retaining full DOM functionality whilst gaining pixel-level manipulation.
How It Works: Three Primitives
The API surface is refreshingly small. Three primitives do all the heavy lifting:
1. The layoutsubtree Attribute
Adding layoutsubtree to a <canvas> element opts its child elements into the browser’s layout and hit-testing system. Without this attribute, canvas children are invisible to layout — they exist in the DOM but have no rendered presence. With it, they behave like normal HTML: they flow, they respond to CSS, they accept pointer events.
<canvas layoutsubtree id="my-canvas">
<div id="content">
<h2>This is real HTML</h2>
<p>Fully accessible, fully styleable.</p>
</div>
</canvas>
2. drawElementImage()
This is the core method. Call it on a 2D canvas context, pass in a child element, and it renders that element’s visual output onto the canvas surface. From that point, you can apply any canvas operation — transforms, compositing, filters, or feed the result into a WebGL pipeline.
const canvas = document.getElementById('my-canvas');
const content = document.getElementById('content');
const ctx = canvas.getContext('2d');
ctx.drawElementImage(content, 0, 0);
3. The paint Event
The paint event fires whenever the canvas’s child elements change — whether through DOM mutation, CSS animation, or user interaction. Combined with requestPaint(), it creates a reactive rendering loop that stays in sync with your HTML without manual polling.
canvas.onpaint = () => {
ctx.reset();
ctx.drawElementImage(content, 0, 0);
};
canvas.requestPaint();
What You Can Build With This
The use cases fall into several compelling categories:
Post-Processing Effects on Live UI
Render a DOM element as a canvas texture, then apply shader-based effects — blur, distortion, colour grading, noise — to live, interactive content. Think frosted glass overlays that actually work, or subtle ambient visual treatments that respond to scroll position.
Page Transitions That Were Previously Impossible
Page-curl effects, 3D fold transitions, liquid morphs between views — all applied to real HTML content rather than screenshots. The content remains interactive throughout the transition.
3D Interfaces with Real HTML
Three.js release 184 introduced an HTMLTexture class built on this API, enabling developers to render live HTML onto 3D surfaces. Imagine a dashboard rendered on a floating panel in a WebGL scene, where buttons actually click and forms actually submit. The InteractionManager forwards pointer events from 3D surfaces to DOM elements without raycasting.
Creative Tooling and Data Visualisation
Design tools, diagram editors, and data visualisation dashboards can now render styled HTML labels, tooltips, and controls directly within their canvas rendering pipeline — no more manually positioning absolutely-placed DOM overlays and hoping they stay aligned.
The Rough Edges (For Now)
It would be irresponsible to present this as production-ready. It is not. Several areas need attention:
Sizing is undercooked. Canvas width/height attributes define the drawing surface independently from CSS sizing, and synchronising the two requires a ResizeObserver and manual bookkeeping. This is a known friction point that the specification will likely address.
Transform synchronisation is manual. CSS transforms on source elements affect hit testing but not canvas drawing. Canvas transforms do not move DOM elements. If you want both to stay aligned during animation, you need to apply transforms to both sides yourself.
Security constraints exist. The specification includes privacy-preserving painting restrictions that prevent certain content (like cross-origin iframes) from being rendered. This is a sensible security boundary, but it limits some use cases.
Browser support is Chromium-only. You need Chrome or Edge 146+ with the canvas-draw-element flag enabled. Firefox and Safari have not signalled implementation timelines. Progressive enhancement is the only responsible adoption strategy for now.
What Development Teams Should Do Right Now
Even in its experimental state, this API is worth paying attention to:
Prototype, don’t ship. Enable the flag in Chrome Canary, build a proof of concept for your most visually ambitious feature, and see what is possible. The API surface is small enough that a meaningful prototype takes hours, not weeks.
Audit your canvas workarounds. If your codebase contains offscreen canvas rendering of DOM content, manual screenshot-to-texture pipelines, or complex overlay positioning systems — this API may eventually replace them entirely.
Watch the specification. The WICG repository is where the specification evolves. If you have use cases that hit current limitations, filing issues now directly shapes the final API.
Plan for progressive enhancement. When this lands in stable browsers, the adoption pattern is straightforward: feature-detect layoutsubtree support, enhance the experience for capable browsers, and fall back to standard DOM rendering elsewhere. The beauty is that the fallback is your existing code.
Why This Matters Beyond the Code
The HTML-in-Canvas API represents a broader shift in browser platform thinking. For years, the web platform added capabilities by building higher-level abstractions — Service Workers for offline, Web Components for encapsulation, CSS Grid for layout. This API takes a different approach: it tears down a wall between two existing systems and lets developers compose them freely.
That compositional philosophy is what makes the web powerful. It is also what makes it hard to replicate on native platforms. A mobile app cannot render its UIKit views as OpenGL textures with three lines of code. The web, increasingly, can.
For teams building creative tools, immersive marketing experiences, data-heavy dashboards, or anything that has ever been described as “we’d love to, but canvas can’t do accessible HTML” — the answer is changing.
How REPTILEHAUS Can Help
At REPTILEHAUS, we specialise in building technically ambitious web applications — from WebGL-powered interfaces to AI-driven tooling. If you are exploring what the HTML-in-Canvas API could unlock for your product, or need help prototyping interactive experiences that push the boundaries of what browsers can do, get in touch. We are already experimenting with this API and would love to help you do the same.
📷 Photo by Matthias Oberholzer on Unsplash



