Engineering Journal
Ginexys
Ginexys

The Document That Wouldn't Stay Still: How a PDF Editor Became a CAD Tool

2026-05-30

TLDR

When users asked if they could drag an extracted table to a different column in our PDF Processor, our initial instinct was to build a canvas overlay with bounding boxes. We quickly realized canvas overlays strip elements out of document flow. By treating the extracted HTML DOM structure (.pdf-zone, .pdf-col, .pdf-region) as the native layout coordinate system, HTML5 drag-and-drop plus insertBefore provided a complete visual layout editor without writing a single line of canvas rendering code.
Architectural PathLayout ModelCSS Reflow BehaviorExport Fidelity
Canvas Bounding Overlaysposition: absolute pixel mathBroken (Elements fall out of document flow)Poor (Positioning artifacts)
Native DOM Layout EngineCSS Grid + DOM insertBefore100% Native (Browser handles reflow)Perfect (Clean semantic HTML)

Visual document editing requires columns and section rearrangement

Our PDF extraction pipeline was working smoothly: tables extracted as clean <table> elements, headers preserved correct <h3> tags, and multi-column pages mapped to responsive CSS Grid containers.

Then came a user request: "The extractor placed this table in column 1, but it belongs in column 2. Can I drag it across?"

In-place text editing was already supported via contentEditable, but moving structural sections across columns required full layout manipulation.


Absolute canvas overlays destroy responsive grid document flow

Our initial design draft reached for canvas overlays, drawing interactive bounding boxes over rendered HTML and listening for drag events on a <canvas> element (similar to Fabric.js or Konva).

We abandoned this approach after writing the prototype. The moment an element is switched to position: absolute for dragging, it drops out of CSS Grid document flow:

+-----------------------------------------------------------------+ 
Canvas Overlay Approach (Abandoned)
[Draw Canvas Bounding Box] -> [position: absolute Pixel Math]
v
[Broken CSS Grid Reflow & Bad Markdown Export]
+-----------------------------------------------------------------+

+-----------------------------------------------------------------+

Native DOM Coordinate System (Adopted)
[CSS Grid Box Model (.pdf-zone)] -> [HTML5 Drag & DOM drop]
v
[100% Native Reflow & Perfect Clean HTML Export]
+-----------------------------------------------------------------+


Browsers calculate layouts natively via Grid containers and client rects

We realized the browser layout engine had already done the work for us:

  1. getBoundingClientRect() provides pixel bounds for any element instantly.
  2. CSS Grid containers automatically reflow child elements when DOM nodes move.
  3. DOM insertion methods (element.before() and element.after()) handle node movement cleanly.

Key engineering insights

  1. Clean drag indicators: To prevent dragover events from spawning thousands of drop indicator DOM nodes, maintain a single indicator instance (_removeIndicator()) and purge it on dragend.
  2. List barrier wrapping: Browsers collapse adjacent <ol> elements during contenteditable backspacing. Wrapping lists in <div class="pdf-list-wrap"> creates a block barrier that prevents collapse.
  3. Monaco layout timing: When embedding Monaco in <dialog> elements, defer .setValue() and .layout() using requestAnimationFrame() until after the dialog paint frame completes.
Rule of thumb: Do not build custom canvas coordinate systems for HTML document editors. The browser DOM combined with CSS Grid is the coordinate system.
Read this post in the full Engineering Journal →