Skip to content

v1.28.0

Choose a tag to compare

@github-actions github-actions released this 02 Jul 07:09

1.28.0 (2026-07-02)

Page Versioning

Every page now keeps a full version history: a docked timeline of every publish and manual save.

page-versioning-walkthrough-tight.mp4
  • Snapshots: every publish and manual save is kept as a version, with timestamps and labels.
  • Preview: view any past version live on the canvas; your working draft is never touched.
  • Restore: load any version back as your draft (the live page stays untouched until you publish).
  • Copy across versions: copy a block/section from an older version into your current page.
  • Component pinning: each version remembers the exact component versions it used, so old versions render the way they were saved. When a pinned component has a newer version, Builder flags it and lets you update.

Component Scripts

Component logic is no longer scattered across individual blocks. Components are now the single place to break logic out of Page Scripts. Each component gets one data script (for dynamic data) and one client script (for reactivity), plus props that drive how dynamic values resolve.

  • Assign dynamic data via the component dict (like data for page scripts), and pass it to the client script through component.component_data.
  • Access the component root element with this in the client script, and read props in both scripts.
  • Style scoping keeps a component's styles contained to that component.
Profile Card Props in Components

Click-Through Rate (CTR) Analytics

Turn on Track Clicks for any link or button and Builder captures its clicks on published pages, then reports click-through rate right in the page's analytics. It is built on the existing page-view to DuckDB to dashboard pipeline, so clicks ride the same view-tracking toggle.

  • Opt-in per block via a Track Clicks toggle in the block's Link section, so only the blocks you choose are tracked (no autocapture noise).
  • Top Clicks and Top Referrers sit side by side in per-page analytics.
  • Click a Top Clicks row to jump straight to that block on the canvas.

Page analytics

Dynamic Custom HTML Attributes

Custom HTML attributes can now take dynamic values, while attribute names and static fallbacks stay editable as plain strings, reusing the existing attribute dynamic value type and the familiar zap-icon dropdown.

Screen.Recording.2026-06-23.at.10.58.10.PM.mp4

Redirect Enhancements

Redirects now come with inline documentation and syntax highlighting, plus options to set the redirect status code and forward query params.

Before After

Custom 404 Page

You can now set a custom page to serve as the site's 404 / not-found page.

Performance

  • Leaner block storage (~39% smaller). Empty defaults (rawStyles:{}, attributes:{}, classes:[], dataKey:null, and the like) are now stripped at the single serialization point used for save, copy/paste, components, templates, and undo/redo. Measured across 5 real template pages, stored size dropped ~39%, which also shrinks every undo/redo snapshot held in memory and cuts JSON.stringify/parse work per commit.
  • Faster page previews. On Frappe v16+, preview images render in-process via the framework's bundled headless Chromium: no external network round-trip, and local /assets and /files resolve during development. Older frameworks fall back to the existing preview_generator service, so nothing breaks on v15.
  • Combined Google Fonts request. Font requests are batched into a single call with a preconnect to gstatic, reducing round-trips when loading fonts on published pages.
  • Request sequencing for component data. A useLatestRequest composable ensures only the latest component data fetch is applied, avoiding stale overwrites and redundant work when props change rapidly.

For the complete list of commits, bug fixes, and refactors, see the full changelog.