« All posts

VectoJS Drops the DOM, Keeps Accessibility Intact

VectoJS renders UIs to a single canvas instead of the DOM, using invisible DOM projections to keep interactive elements accessible to screen readers.

VectoJS rejects the assumption every UI framework of the last decade has shared: that an application must ultimately be a tree of HTML elements. Instead of managing or compiling around the DOM like React, Svelte, or Tailwind do, VectoJS renders an entire app to a single canvas element. Buttons, lists, and thousands of live data points exist as plain TypeScript objects with position, size, and a render() method, forming a retained scene graph redrawn every frame like a game engine.

The classic weakness of canvas UIs is accessibility — screen readers see one opaque bitmap and Ctrl+F finds nothing. VectoJS addresses this by projecting an invisible but real DOM node (a button, input, or link) over every interactive entity, keeping its transform synced to the canvas each frame. Keyboard focus, pointer events, and screen readers all interact with that genuine DOM element, while non-interactive objects like particles or glyphs cost nothing beyond a draw call, since the sync overhead is applied only where it's actually needed.

That split lets VectoJS handle workloads that typically break DOM-based UIs: node-graph editors with hundreds of draggable, connected nodes; WebGPU-driven particle systems moving tens of thousands of points (with a CPU fallback); and text readers that reflow entire books around the cursor in real time. The project is MIT-licensed and open on GitHub, with live demos showing FPS and entity counts so developers can benchmark performance on their own hardware.