![Natalia Markoborodova](https://web.dev/images/authors/nmarkoborodova.jpg) Natalia Markoborodova [X](https://twitter.com/nmarkoborodova) [GitHub](https://github.com/ewewraw) [LinkedIn](https://www.linkedin.com/in/natalia-markoborodova) [Bluesky](https://bsky.app/profile/nmarkoborodova.bsky.social)


Published: October 26, 2026

<br />

Following a [successful origin trial](https://developer.chrome.com/blog/html-in-canvas-origin-trial.md.txt), 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](https://www.youtube.com/watch?v=mB0eWkWubuk) 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()`](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/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 (<kbd>Ctrl</kbd>/<kbd>Cmd</kbd>+<kbd>F</kbd>), 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

> [!NOTE]
> **Note:** For more information, see the [HTML-in-Canvas technical documentation](https://developer.chrome.com/docs/web-platform/html-in-canvas.md.txt).

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](https://developer.chrome.com/docs/web-platform/html-in-canvas/concepts.md.txt#prepare) and how to [declare HTML elements to be drawn independently](https://developer.chrome.com/docs/web-platform/html-in-canvas/concepts.md.txt#drawable).

   ```javascript
   <!-- 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](https://developer.chrome.com/docs/web-platform/html-in-canvas/2d.md.txt), [WebGL](https://developer.chrome.com/docs/web-platform/html-in-canvas/webgl.md.txt), or [WebGPU](https://developer.chrome.com/docs/web-platform/html-in-canvas/webgpu.md.txt) context.

   ```javascript
   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.

   ```javascript
   // 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:

> [!NOTE]
> **Note:** The listed tools are community libraries and are third-party projects. They aren't developed, maintained, or officially supported by Google or the Chrome team.

- **Three.js** : offers experimental support using `THREE.HTMLTexture`.

  ```javascript
  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()`.

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

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

  ```javascript
  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:

```javascript
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`).

> [!NOTE]
> **Note:** The listed tools are community libraries and are third-party projects. They aren't developed, maintained, or officially supported by Google or the Chrome team.

## Next steps

- Explore the complete [Chrome for Developers HTML-in-Canvas documentation](https://developer.chrome.com/docs/web-platform/html-in-canvas.md.txt).
- Upgrade coding assistants using [Modern Web Guidance](https://developer.chrome.com/docs/modern-web-guidance.md.txt).
- Share feedback on the [WICG GitHub repository](https://github.com/WICG/html-in-canvas/issues).
- Check out the [HTML-in-Canvas community demos](https://github.com/GoogleChromeLabs/css-web-ui-demos/blob/main/html-in-canvas/awesome-html-in-canvas.md).