Back to Blog
News

Editor Update: Pages That Flow, Headings That Stay Headings

The biggest release the template editor has had this year — and almost all of it is about the boring stuff that decides whether an editor feels solid: where content lands when a page fills up, whether the caret is where you clicked, and whether undo still works after you touch a table.

August 2026·8 min read

The short version

  • Content now flows onto the next page when the current one is full — instead of one page growing past A4 forever.
  • The Elements panel, the floating "+" menu, and drag-and-drop all place blocks through the same validated rules.
  • Typing in a Heading block stays a heading. Previously it silently became body text.
  • Variables insert cleanly from both the toolbar and the { shortcut, without eating text you already typed.
  • Undo keeps working after table edits. It used to switch off globally the first time you added a row.
  • The Layers panel reads "Paragraph" and "Heading 1" instead of "P" and "H1".

GJSDocs templates are paginated documents, not web pages. A4 has a hard bottom edge, and every feature in the editor has to respect it — otherwise what you build looks nothing like the PDF that comes out the other end. Most of this release is about closing the gap between those two things.

Pages fill up, then flow

Clicking a block in the Elements panel used to append it to the current page and stop there. Click twenty times and you got one page twenty items tall — visually past the A4 boundary, and a surprise at export time.

Now every click-insert reflows the document afterwards. When a page no longer fits A4, the overflow spills onto the next page — the same behaviour you already got from typing past the bottom of a page. Bulk inserts reconcile once at the end rather than after every item, so adding a whole section doesn't make the canvas flicker through twenty layout passes.

The stray page between pages

A related bug went with it. If you filled page 1, added page 2, then went back and dropped one more element at the end of page 1, you ended up with three pages — a nearly empty one wedged in the middle holding that single element. Overflow now goes to the page that already follows, and only creates a new page when there isn't one. Fill page 1, add page 2, add to page 1 → still two pages.

One set of rules for every way to add a block

There are three ways to get a block onto the canvas: click it in the Elements panel, click it in the floating + menu next to your selection, or drag it. Those were three separate implementations with three sets of rules, which is exactly how you end up with a click that builds something drag-and-drop would have refused — a page nested inside a page being the one people actually hit.

All three now go through a single placement path that validates every candidate position before it commits. Whole-page blocks are drag-only by design, since "insert a page next to this paragraph" has no sensible answer — the canvas toolbar's Add Page button is the deliberate way to do that.

Headings stay headings

This one was subtle enough to be genuinely maddening. You'd insert a Heading block, type your title, and the text would come out styled as body copy — always in Firefox, intermittently in Chrome. The heading was there; your text just wasn't inside it.

The block was built as a heading wrapped in a text container, so the editable region was the wrapper and the caret landed before the heading rather than in it. Everything you typed became its sibling. The heading is now the text component itself, so the caret has nowhere else to go. Section blocks that contain headings get the same treatment on import.

Typing lands where you clicked

After inserting a block you can type immediately — the caret is placed at the start of what you just added, whether it came from the panel, the + menu, or a drop. Before, the caret often stayed wherever it was, so the first thing you typed went into the previous block or nowhere at all.

Underneath, the whole edit-mode handoff was rebuilt. Pressing Enter, Backspace, or an arrow key to move between blocks used to run through a chain of fixed delays that guessed at how long rendering would take. Under fast typing those chains overlapped: keystrokes got dropped, undo steps were left half-open, and the editor could wedge itself into a state where input stopped registering entirely.

Transitions are now driven by the editor's own render and focus events rather than timers, only one runs at a time, and there's a watchdog so a missing event can never freeze input. It's the difference between an editor that keeps up with a fast typist and one that doesn't.

Variables insert without eating your text

Both ways of inserting a variable — the toolbar dropdown and typing { to filter — now share one implementation. The old one could mistake a caret sitting on an element boundary for a selection spanning whole child nodes, and clear a paragraph you'd just written. Insertion also never consumes a highlighted selection by accident.

Undo works after table edits

Adding a row, deleting a column, merging cells — any table operation used to leave undo tracking switched off for the rest of the session. Not just for the table: for the whole document. You'd add a row, keep working, hit Ctrl+Z twenty minutes later and nothing would happen.

Table operations now record as a single undo step each — one Ctrl+Z removes the row you added — and tracking is never left disabled. Cell selection and the table toolbar reposition correctly afterwards too.

The Layers panel speaks English

Content dropped in by section blocks had no type of its own, so the Layers panel and the selection badge fell back to raw tag names: Ul, Li, P, Div. Navigating a long template meant reading HTML.

Everything now has a readable name — List, Numbered List, List Item, Paragraph, Heading 1 through Heading 6, Divider, Table Row. Small change, and the single most noticeable one if you build long documents.

Canvas fixes you'll feel before you notice

The top of page 1 is no longer clipped

The canvas frame was sized for a single-page device preview rather than a continuous scroll of pages, which meant it overflowed its container. Focusing a text block could scroll the outer wrapper and cut off the top of the first page. The frame now matches its container, and the document itself is the only thing that scrolls.

The caret can't park below the fold

Because the frame reported a taller viewport than was actually visible, "scroll the caret into view" sometimes scrolled it into the clipped region under the canvas. Same root cause, same fix.

A real scrollbar, in every browser

The canvas scrollbar now sits at the edge of the canvas column instead of floating inset from it, and it's styled to match the rest of the app in Firefox as well as Chrome. There's also trailing room at the end of the document so the last page scrolls clear of the floating page controls.

The floating menu stops leaving debris

Selecting components faster than the menu could render used to leave orphaned icon clusters at stale positions, and a delayed re-select could steal your selection a full second after you'd moved on. Both are gone.

The blocks panel renders on first open

An empty Elements panel on first mount — fixed by keeping the editor's own load event out of the tab-detection logic it was quietly corrupting. Rapid tab switching also no longer stacks up render passes.

Pagination measures after fonts load

Page heights were sometimes measured before web fonts had swapped in, which produced wrong page breaks on slow connections. Measurement now waits for fonts to be ready instead of a fixed delay.

Why so much of this is invisible

Almost every bug above came from the same class of mistake: code that waited a fixed number of milliseconds and hoped the browser had finished. That works on a fast machine with a small document and falls apart on a slow one with a long template — which is why these problems were so hard to pin down and so easy to dismiss as "it works on my machine".

This release replaces those guesses with actual signals — render events, font-loading promises, layout frames — and locks the behaviour in with tests. Pagination, block insertion, keyboard navigation, variable insertion, table commands, and component naming all gained dedicated test suites, alongside browser-level end-to-end tests that drive a real editor: click-insert reflow, keyboard race conditions, the heading block, and visual snapshots of two-page documents so page-break regressions get caught before you see them.

Nothing to do on your side

All of this is live. Existing templates keep working — no migration, no re-saving, no settings to change. If you had a template with a page that had quietly grown past A4, opening it will reflow the overflow onto a following page, which is what the PDF was doing anyway.

If something in the editor still feels off, tell us — the fastest route is @gjsdocs on X. Several fixes in this release came straight from someone describing exactly what they clicked before it broke.

Try the editor

Build a template once, connect your data, and generate documents in seconds. Free to start, no credit card.

Start free