TL;DR

Chrome vừa bật cờ cho html-in-canvas — một API WICG mới cho phép render bất kỳ phần DOM nào (form, video, dashboard, map) trực tiếp vào <canvas> 2D, WebGL, hoặc WebGPU. Khác với hack <foreignObject> cũ, nội dung vẫn fully interactive: bạn có thể gõ vào một <input> được dán lên mặt một khối 3D đang xoay. Feature đang nằm sau flag chrome://flags/#canvas-draw-element, Origin Trial M148–M151.

What's new

Trước đây, muốn đưa HTML lên canvas, web dev phải gói DOM vào <foreignObject> của SVG rồi blit vào canvas — một hack bẩn, mất interactivity, mất accessibility, render không nhất quán giữa các font/CSS. html-in-canvas giải quyết triệt để bằng ba primitive mới:

  • layoutsubtree — attribute mới trên <canvas>, opt-in các phần tử con vào layout + hit testing, nhưng giữ chúng invisible cho đến khi được vẽ.
  • drawElementImage(element, ...) — method 2D context; vẽ trạng thái hiện tại của phần tử con vào canvas và trả về CSS transform để DOM và pixel render luôn đồng bộ vị trí.
  • paint event + requestPaint() — fire khi rendering của con thay đổi, cho phép redraw từng frame hiệu quả.

WebGL có thêm texElementImage2D(), WebGPU có copyElementImageToTexture() — bind render của element làm GPU texture native, không cần serialize qua image bitmap mỗi frame.

Why it matters

Đây là thay đổi lớn nhất của Canvas API kể từ OffscreenCanvas. Lý do: nó phá vỡ bức tường giữa "DOM render đẹp nhưng khó can thiệp" và "canvas linh hoạt nhưng phải tự layout chữ/form". Giờ bạn có thể:

  • Build HUD cho WebGL game bằng HTML/CSS thường, không cần reimplement text layout.
  • Đưa dashboard React vào cảnh three.js, vẫn có hover, tooltip, keyboard nav.
  • Apply shader GLSL lên một <form> thật — distort, ripple, CRT, frosted glass — mà form vẫn nhận input.

"The web is fun again" — đó là phản ứng của cộng đồng frontend, vì một giới hạn nhiều năm cuối cùng đã bị gỡ.

Technical facts

PrimitiveContextCông dụng
layoutsubtreeattributeOpt-in children vào layout & hit testing
drawElementImage()Canvas 2DVẽ DOM element vào canvas, trả về transform
texElementImage2D()WebGLBind render làm texture WebGL
copyElementImageToTexture()WebGPUCopy render sang GPU texture WebGPU
paint eventeventFire khi child rendering thay đổi

Có sẵn trong Chrome CanaryBrave Stable (Chromium 147+). Bật cờ chrome://flags/#canvas-draw-element rồi restart.

Comparison — vs foreignObject hack

Tiêu chíSVG foreignObject (cũ)html-in-canvas (mới)
Input có gõ được?❌ pixel đông cứng✅ focus, type, tab, hover
Accessibility tree❌ bị cắt rời✅ khớp DOM thật
WebGL / WebGPU texture❌ phải re-serialize mỗi frame✅ API native
CSS fidelity (font, filter, …)⚠️ mảnh vỡ, không đều✅ full Blink render
Update động⚠️ rebuild mỗi tickpaint event

Use cases

  • 3D Room demo — three.js dựng phòng có monitor, TV, poster; nội dung trên mỗi mặt là HTML live (dashboard chart, CSS animation, form).
  • Accessible charts — bar/pie chart bằng DOM thật, render lên canvas, ARIA + keyboard nav vẫn hoạt động.
  • CSS-to-Shader pipeline — dán fragment shader GLSL lên một form HTML; gõ vào ô input thấy pixel méo theo shader nhưng text vẫn nhập được.
  • Frosted glass backdrop — panel kéo thả với blur nền, compose bằng WebGL.
  • HTML-to-image export — social card, OG image, receipt generate client-side với CSS fidelity 100%.

Limitations & pricing

Miễn phí, là primitive của nền web. Nhưng còn nhiều giới hạn:

  • Chỉ Chromium — Chrome Canary & Brave Stable 147+. Firefox đang cân nhắc, WebKit chưa lên tiếng.
  • Cross-origin content (iframe ngoài, ảnh ngoài) bị loại khỏi bitmap render vì bảo mật.
  • System colors, theme, visited link, autofill text bị strip.
  • Không có subpixel antialiasing.
  • CSS transforms trên canvas children bị bỏ qua lúc vẽ, nhưng vẫn áp dụng cho hit testing & a11y — đây là ràng buộc cố ý.
  • Shape API còn thay đổi — đây là WICG proposal, chưa phải standard cố định.

What's next

Origin Trial M148–M151 mở ra test thực tế ở quy mô lớn. Nhóm three.js đã có branch thử nghiệm wire texElementImage2D vào CanvasTexture — tức stack 3D phổ biến nhất của web đã sẵn sàng tích hợp ngay khi API chín. Các bước kế: WebGPU path đầy đủ, câu chuyện cross-origin, vị trí chính thức của các engine khác.

Nguồn: WICG/html-in-canvas, html-in-canvas.dev, Intent to Experiment (blink-dev), Frontend Masters, Imiel Visser — drawElementImage guide.