Skip to content
Changelog

What shipped, and when

Every release is listed here with the packages it changed — all packages share one version number.

SepOct
20 releases in 32 days
  • Fix@templatical/editor

    The AI button renders with the rest of the header

  • Fix@templatical/editor

    The AI header button matches the other header buttons

Read the full notes for 0.51.1
  • Feature@templatical/editor@templatical/quality@templatical/template-tools

    Add default-on compatibility lint for authored pass-through HTML and CSS, using a pinned caniemail snapshot, plus an explicit compiled-HTML Gmail size check. Agents and headless callers receive a concrete suggestion and reference on every issue, with affected clients and an excerpt when available. The editor shows suggestions and source links, and offers an on-demand Check size action when its render provider can compile without saving. templatical validate --html reports htmlBytes and a clipping warning.

  • Feature@templatical/editor

    @templatical/quality is an optional dependency of the editor and installs by default. Leaving it out is supported: the editor works without it and hides the Issues tab.

  • Feature@templatical/quality

    lintTemplate now runs the deliverability category by default. Agents can use lintDeliverability, DELIVERABILITY_RULES, localized messages, DEFAULT_SHORTENER_HOSTS, and DEFAULT_DELIVERABILITY_THRESHOLDS directly. The category flags deliverability.link-text-domain-mismatch (warning), deliverability.url-shortener (warning), deliverability.ip-address-url (warning), and deliverability.low-text (info). Each rule reports a JSON-detectable content cue; none auto-fixes or scores a template.

  • Feature@templatical/editor@templatical/types

    Custom merge-tag syntaxes get autocomplete through opener and closer

  • Feature@templatical/editor

    init({ ai }): bring your own AI backend. Each feature is labelled as AI, in every editor locale:

  • Feature@templatical/types

    AI as a bring-your-own contract (BYO contract):

  • Feature@templatical/ai-kit

    New package @templatical/ai-kit, MIT and with no LLM SDK dependency: the editor's AI over your own backend.

  • Feature@templatical/core

    The collaboration controller applies an AI turn's operations as this session's batches, marked origin: 'ai', one undo step per turn (applyOperations). invertOperations now comes from @templatical/types; core re-exports it.

Read the full notes for 0.50.0
4 days
  • Feature@templatical/template-tools

    edit speaks operations vocabulary v2

  • Feature@templatical/types

    Operations vocabulary v2, the engine that applies it, and the collaboration contract

  • Feature@templatical/editor

    Real-time collaboration in the editor over your backend, and agents' edits named

  • Feature@templatical/core

    Real-time collaboration over a provider

Read the full notes for 0.49.0
4 days
  • Feature@templatical/editor@templatical/import-beefree@templatical/import-unlayer@templatical/types

    Size an image by its height with the aspect ratio locked. When the image file's size is known, the image settings show a link toggle on the Height row, on by default: typing a height sets the width from the file's ratio, and a height that would make the image wider than its column sets it to Full width, with a note of the height it lands at. Under the lock the stored height stays unset, because a stored height squashes an image on any phone narrower than its width (MJML shrinks the width and keeps the height).

  • Feature@templatical/editor@templatical/import-easy-email-pro@templatical/import-mjml@templatical/quality@templatical/renderer@templatical/template-tools@templatical/types

    Sections can render as heroes

  • Feature@templatical/editor@templatical/renderer@templatical/types

    Titles stay bold while you edit them. A title showed at weight 700 on the canvas and in the email, but its edit surface showed it at 400, so the text turned lighter, and could rewrap, the moment editing started. The canvas, the edit surface and the exported heading now all use 700, which @templatical/types exports as TITLE_FONT_WEIGHT. The renderer writes it onto the heading as font-weight:700, so emails look as before in clients that already bold headings, and a page that resets heading styles (Tailwind's preflight, for one) no longer shows the email's titles at regular weight. With shadowDom: false on such a page, the canvas title was regular too; it is now bold.

  • Feature@templatical/import-mjml@templatical/renderer

    An image set narrower than its column keeps its width on phones (#861). The renderer set fluid-on-mobile on every mj-image through <mj-attributes>, so a 120px logo grew to the whole column on a phone while the editor's mobile preview showed it at 120px, and an image with a set height was stretched out of shape (120×40 became 355×40 on a 375px phone). The attribute is now set per image, only on one that fills its column on desktop: width: "full", or a pixel width at or above the room MJML gives it, which is the column less the side padding and border of the wrapper band, the section and the image. Images wider than the phone still shrink to fit, and video thumbnails follow the same rule.

  • Fix@templatical/media-library

    The standalone media library (init() and MediaLibraryModal) now renders as designed on host pages without a CSS reset. A reset such as Tailwind's preflight hid all of this. Inside the editor, the media library already rendered correctly.

  • Fix@templatical/editor@templatical/import-mjml@templatical/renderer

    Fractional padding and borders no longer shift which images fill their column on phones

  • Fix@templatical/import-beefree@templatical/import-chamaileon@templatical/import-easy-email-pro@templatical/import-html@templatical/import-mjml@templatical/import-stripo@templatical/import-topol@templatical/import-unlayer

    Imported images come in at the width the source email shows them, and every importer decides width: "full" by one rule. A missing width, 100%, or a px width that reaches the image's room (its column less its own side padding, and border where the importer reads one) is "full"; a narrower px width stays px; a percentage under 100% becomes px of the room and is reported approximated, since a px width keeps its size on a phone.

Read the full notes for 0.48.0
  • Feature@templatical/editor@templatical/quality@templatical/renderer@templatical/template-tools@templatical/types

    Sections and wrapper bands take a background image

  • Feature@templatical/editor@templatical/renderer@templatical/types

    Titles and paragraphs enter editing in place. The edit surface used to add a dashed border and 8px of padding around the text, which made the text column 18px narrower and could move its line breaks; its dashed ring is now an outline drawn 4px outside the text, so nothing moves. Titles also kept a different line height in each place: 1.5 while editing, 1.25 on the canvas and 1.3 in the email. All three now use 1.3, which @templatical/types exports as TITLE_LINE_HEIGHT, so sent emails are unchanged and a canvas title is about 1px taller per line.

  • Feature@templatical/import-beefree@templatical/import-chamaileon@templatical/import-easy-email-pro@templatical/import-html@templatical/import-mjml@templatical/import-stripo@templatical/import-topol@templatical/import-unlayer

    Importers bring section and wrapper background images across

  • Feature@templatical/editor@templatical/renderer@templatical/types

    A blank line typed in a title or paragraph is kept on the canvas and in the email. TipTap stores it as an empty <p></p>, which showed a line tall only while editing: on the canvas and in mail clients an empty paragraph has no height. The renderer and the canvas now fill each empty paragraph with &nbsp;, so the blank line is one line tall everywhere. Templates that already contain blank lines get taller in sent emails, matching what the author saw while editing. The stored content is unchanged, and a paragraph with no text at all still renders nothing. @templatical/types exports the rule as fillEmptyParagraphs, with isBlankRichText for the empty check.

  • Feature@templatical/template-tools

    Add templatical custom-block validate|render|fetch and live --custom-block [--host] for authoring custom block definitions. validate checks the definition against a generated custom-block-schema.json, cross-checks the Liquid template against its fields, lints the rendered HTML for email-client safety, and proves it renders through MJML. checkCustomBlock also takes the object a definition module exports, dataSource included, so the same check can run in your own tests. Accessibility warnings cover vague link text, links with no name, layout tables without role="presentation" and low contrast between inline colours. The live preview shows the block in its edge-case states, and with --fetch adds one filled from the real endpoint. That request, and the editor's Fetch button, run a preview-only dataSourcePreview recipe; the bridge makes those requests from Node, reading credentials from environment variables, so they never reach the page.

  • Feature@templatical/editor@templatical/renderer@templatical/types

    Custom-block stylesheets now reach a render backend. The editor copies each definition's stylesheet onto its blocks as renderedStylesheet when it pre-renders renderedHtml, for a render provider's payload and before Cloud saves. renderToMjml emits those copies when no getCustomBlockStylesheet is passed, so renderToMjml(payload.content) keeps a custom block's media queries and hover rules with no extra wiring. A resolver, when passed, still decides every type.

  • Feature@templatical/editor@templatical/renderer@templatical/types

    The editor canvas shows a font with the same fallbacks as the email. A title, button, menu, table or countdown in a font the browser doesn't have, or a template font such as Helvetica Neue, used to preview in the browser's default serif while the email fell back to defaultFallback (Arial, sans-serif unless configured). The canvas, preview mode and the block previews now apply the renderer's own rule: a single unknown font previews as 'Helvetica Neue', Arial, sans-serif, a built-in font as its stack, and a custom font with its fallback. @templatical/types exports the rule as resolveFontStack.

  • Fix@templatical/editor

    The video toolbar's Width control now shows a width that isn't one of its presets. A video with any other width, such as the 600px the BeeFree importer writes for a video with no explicit width, or an integer in API- or agent-written JSON, showed a blank select, and touching it overwrote the width. Width now works like the image toolbar's: Full Width, 300px, 400px, 500px or Custom, with a px input for Custom. Any other width reads as Custom with its value in the input, so authors can see it and type any width.

  • Fix@templatical/editor

    Dropping an image now shows the uploading state while it uploads. An image dropped on an image block on the canvas, its URL field in the sidebar, or a custom block's image field used to clear the drop overlay as soon as the upload started, so the spinner and "Uploading…" never appeared.

  • Fix@templatical/editor

    The image toolbar's alt text field now pulses every time a picked or dropped image fills it in. It used to pulse only for the first image with alt text and stay still for every later one, even on another image block.

  • Fix@templatical/editor

    The text toolbar's line-height and letter-spacing selects show their placeholders and the letter-spacing "Normal" option in the editor's locale. They used to read LH, LS and Normal in every locale. The placeholders stay short, such as ZH / ZA in German and 行間 / 字間 in Japanese, and each select's tooltip and accessible label still give the full name.

  • Fix@templatical/editor

    A top-level block dragged into a section column that already holds blocks now lands where it's dropped. It used to land at the top of the column whatever the drop position, because the column's drop index was counted with a selector only the canvas's own items match. Drops into an empty column, between columns and sections, out to the canvas and within the canvas are unchanged.

  • Fix@templatical/editor

    The paragraph toolbar's font size, line height and letter spacing selects show the value in use when they don't offer it. Imported or pasted text often carries one, such as 15px text or a 1.3 line height, and the select showed nothing. The value is now listed first, like an unlisted font. A CSS-wide keyword such as inherit shows the select's placeholder.

  • Fix@templatical/editor

    The editor's interface now renders as designed in the default Shadow DOM mount, and on host pages without a CSS reset. A host reset such as Tailwind's preflight hid all of this in light-DOM mounts.

  • Fix@templatical/editor

    The dark-mode canvas preview now inverts section wrapper frames and layout bands. A section's wrapper frame stayed light while the section inside it turned dark, and with a layout, the band around the email (and the whole email inside it) stayed light in the preview. Both now invert together with the content they hold, once, and images on them still show as they are.

Read the full notes for 0.47.0
  • Feature@templatical/quality

    New link.relative-url rule (warning). It flags a link whose URL starts with /, ./, ../ or ?, or is protocol-relative (//host). A sent email has no page address to resolve such a URL against, so the link breaks in the inbox. Only these path-shaped prefixes count, so a URL that opens with a merge tag ({{ unsubscribe_url }}) is never flagged. Lower it, raise it or turn it off through links.rules.

  • Feature@templatical/editor@templatical/types

    Add editor.insertBlock(block) for inserting a block from outside the editor

  • Feature@templatical/editor@templatical/import-beefree@templatical/import-chamaileon@templatical/import-easy-email-pro@templatical/import-html@templatical/import-mjml@templatical/import-stripo@templatical/import-topol@templatical/import-unlayer@templatical/renderer@templatical/types

    Imported templates keep their font fallbacks. Every importer used to cut a font-family stack down to its first family, so Montserrat, Trebuchet MS, sans-serif became Montserrat, and a mail client without Montserrat fell back to its own default (Times New Roman in Outlook on Windows). This included paragraph text, which the importers style with an inline span. The whole stack is now kept, with double-quoted names re-quoted in single quotes. A stack that is exactly a built-in font's own, such as Arial, sans-serif, is still stored as the bare name, since the renderer expands it back the same way. Easy Email Pro's page font used to be kept as written, so a value such as inherit became the template font; a value a browser would ignore now falls back to the default font.

  • Fix@templatical/editor

    Preview mode no longer shows a section column's drop chrome. An empty column kept the dashed border, the "Drop here" hint and the 60px drop height there, though preview shows the email as it will be sent. In preview an empty column is now a blank 34px, the height of the placeholder the renderer gives it in the sent email. A column whose blocks the condition preview hides collapses to nothing, as the email's column does when the condition is false. Editing is unchanged.

  • Fix@templatical/editor

    The rich-text link dialog no longer turns a relative path into a broken URL. /contact, ./pricing, ../pricing and ?ref=footer are stored as typed (where they used to become https:///contact), matching what the button and image URL fields already did, and the new link.relative-url quality rule flags them. A protocol-relative //cdn.example.com/x becomes https://cdn.example.com/x (it used to become https:////cdn.example.com/x). The paletteBlocks JSDoc now says that an empty array shows the full default palette, as omitting the option does.

  • Fix@templatical/renderer

    A font stack that quotes a family with double quotes, such as "Helvetica Neue", Arial, sans-serif, no longer drops the font from the email. The renderer wrote font-family into its MJML attribute unescaped, so the first " ended the attribute. MJML then reported invalid attributes and compiled the font as font-family:;. For the template font, that meant every text block fell back to the mail client's default. These values come from imported templates (Easy Email Pro keeps the page's stack as written) and from hand-written or generated JSON. The template font and the title, button, menu and table fonts now escape &, <, > and ". Single quotes are left as they are, so stacks like 'Times New Roman', serif and custom fonts render byte-for-byte as before.

  • Fix@templatical/editor

    A merge tag or logic tag typed out in full in a paragraph or title, such as {{first_name}}, {{ first_name}} or {% if vip %}, turns into a chip again as its closing character is typed. Since 0.43.3 it stayed as plain text and the suggestion list stayed open. Picking a tag from the suggestion list or the picker was not affected.

  • Fix@templatical/import-mjml

    The MJML importer now reads back the button width, the per-corner radii, the borders and the button font that the renderer writes, so a rendered template survives a re-import with all of them.

  • Fix@templatical/editor

    Merge-tag type-ahead now follows editor.setMergeTags() in a paragraph or title that is already open. The suggestion list was read once when the block opened for editing, so typing {{ kept offering the previous tags — including ones you had just removed — until the block was closed and reopened.

  • Fix@templatical/types

    Blocks no longer share nested objects with their defaults or with each other

  • Fix@templatical/template-tools

    The SectionWrapper description in schema.json no longer calls the wrapper a full-width band

Read the full notes for 0.46.0
2 days
  • Feature@templatical/editor@templatical/import-mjml@templatical/import-topol@templatical/renderer@templatical/types

    Social icons take a tone, separate from their shape

  • Fix@templatical/import-mjml@templatical/renderer

    A full-width button is now clickable across its whole fill in the compiled email, not only on its label. MJML gives a button's <a> a width only for a px width, so for width: "full" it widened the button's table and left the <a> at display:inline-block, the size of its label. A full-width button's mj-button now carries the class tpl-button-full, and every template's <mj-style inline="inline"> block ends with .tpl-button-full a { display: block !important; }: mjml inlines it onto the link, and MRML's default build keeps it as a <style> rule. That one line is new in every template's MJML. With mjml, juice drops the rule when nothing matches, so the compiled HTML of a template without a full-width button is unchanged. Outlook on Windows ignores display:block, so there the link stays the size of its label, as it does for every MJML button. BUTTON_FULL_WIDTH_CSS_CLASS is exported for blockRenderers overrides of the button. The MJML importer treats tpl-button-full as the renderer's own class, so importing a rendered template doesn't report it as dropped consumer CSS. Fixes #868.

  • Fix@templatical/editor

    A section column with blocks in it is now as tall as its blocks on the canvas. Every column kept the 60px drop-zone minimum, so a short band, such as a one-line strip or a footer note, looked taller while editing than in the sent email. A column showing no blocks keeps the 60px drop target: an empty column, and one whose blocks the condition preview hides. A column keeps it for the whole drag of its last shown block. The whole visible column takes drops, including the space below a short column's blocks.

  • Fix@templatical/editor

    The font pickers show the font in use when they don't offer it. A font the picker doesn't list, such as one from imported content or a built-in excluded by builtIns, or a stack written by the API or an agent, such as Georgia, serif, matched no option. The block toolbars' select showed blank, the paragraph toolbar's showed "Default", and Template Settings showed the default font while the email rendered another. A stack whose first family is listed now selects that family's option; any other font is listed first, labelled by its first family. A CSS-wide keyword such as inherit, or a blank value, shows as no font: the select's own option for that, such as "Use template font" or "Default".

Read the full notes for 0.45.0
4 days
  • Fix@templatical/editor

    Keyboard focus stays in place in the saved blocks browser

  • Fix@templatical/editor

    The saved-block delete confirm stays on one line

  • Fix@templatical/editor

    init() and initCloud() now check layout and content when they are called, before they touch the container. A call whose layout or content the editor refuses (such as a layout without exactly one legal slot, or content holding a slot or wrapper block) rejects at once with the same error as before, and leaves the container and its editor exactly as they were. The check used to run after the call had taken the container over: the rejected call unmounted the editor already there and left the container blank, and an earlier call still loading on that container resolved with an editor that never mounted. A rejected initCloud() call now also makes no auth, health or plan request, and in shadow DOM mode a rejected call no longer attaches a shadow root.

  • Fix@templatical/editor

    init() now mounts on a copy of the config you pass and never writes to it, as initCloud() already did. It used to write the normalized layout and content back onto your object, so a frozen config that carried either one, such as Immer state or an Object.freezed constant, threw TypeError: Cannot assign to read only property. Reassigning a key on that object after init(), such as onChange, no longer reaches the editor; for a handler that changes over time, pass a function that calls the current one.

  • Fix@templatical/editor

    Saved-block surfaces now have rounded corners

Read the full notes for 0.44.3
  • Fix@templatical/renderer

    Text in a right-to-left email now runs right-to-left in the compiled HTML, not only in the editor. The renderer put direction="rtl" on mj-section and mj-group, but MJML gives every mj-column and mj-wrapper a default direction="ltr" and inlines it on the element. That inline style overrode <html dir="rtl">, so paragraphs were right-aligned but laid out left-to-right, and numbers and punctuation landed on the wrong side. RTL templates now also emit direction="rtl" on mj-column and mj-wrapper. LTR output is unchanged. Fixes #872.

Read the full notes for 0.44.2
  • Fix@templatical/editor

    When init() or initCloud() is called again on a container before an earlier call on it has resolved, the later call now keeps the container, whichever call finishes first. The earlier call resolves with an editor that never mounts, and whose unmount() does nothing. The call that finished last used to replace the other's editor: under React StrictMode in development, the cancelled first call could finish last on a cold load, and the documented cleanup then unmounted it, leaving a blank editor. initCloud() now also rejects a container selector that matches nothing before it makes any request.

  • Fix@templatical/editor

    Saved-block cards no longer nest their actions inside a button

Read the full notes for 0.44.1
  • Feature@templatical/editor

    The editor's type declarations no longer import any package. They imported @templatical/types, @templatical/core, @templatical/quality and vue, none of which the editor declares, so with only the editor installed TypeScript reported Cannot find module under skipLibCheck: false and typed those parts as any otherwise, letting a call like init({ content: 42 }) compile. The types they reference are now part of the editor's own declarations.

  • Fix@templatical/editor

    pusher-js is now declared as an optional peer. The editor imports it for initCloud() realtime, and without the declaration a production vite build of an app that doesn't install it failed with failed to resolve import "pusher-js", while the dev server ran normally.

  • Fix@templatical/editor@templatical/types

    safeClone drops only a reference back to an ancestor, so an object reached by two paths is copied into both places. It dropped the second visit before, which lost data from editor.getContent() and undo snapshots whenever two blocks shared an object, such as two custom blocks of a type whose repeatable field has a default.

  • Fix@templatical/editor

    The editor works on a copy of the content it receives: init({ content }), setContent(), create({ content }), a templates.load result and version-history content. Edits never change the caller's object, and content from another Vue's reactive(), a ref()'s .value or markRaw(), or frozen store state, now edits normally. The editor held the object it was given before: an app's own reactive object kept text and settings edits off the canvas and the properties panel, and frozen state threw on the first edit.

  • Fix@templatical/editor

    The Issues tab goes away when @templatical/quality isn't installed: the editor removes it once the package's import fails, and switches to the Content tab if Issues was open. Without the package the tab used to stay and open onto an empty panel.

Read the full notes for 0.44.0
2 days
  • Fix@templatical/editor

    An editor instance's unmount() now tears down only that instance. Once another init() on the same container has replaced it, calling the old instance's unmount() does nothing instead of unmounting the replacement — which left a blank editor under React StrictMode when a bundler settled both mounts in the same tick, as webpack's shared chunk loading can. The top-level unmount() export still tears down the most recently mounted editor.

  • Fix@templatical/editor

    The editor footer draws the Templatical mark inline instead of loading https://templatical.com/logo.svg, so init() makes no requests to Templatical. The footer no longer carries an "Open Source" link: the editor is source-available under FSL-1.1-MIT. branding: false still hides the footer.

Read the full notes for 0.43.3
3 days
  • Fix@templatical/editor@templatical/media-library

    Fix the media library's Edit dialog replacing the image with an 80% crop when only the alt text or filename changed (#834). The crop box now starts on the whole image, and Save sends a new file only after the crop moves or a max width or height shrinks the image.

Read the full notes for 0.43.2
2 days
  • Fix@templatical/editor

    Fix merge and logic tag tooltip contrast inside email content when the editor is in dark mode.

Read the full notes for 0.43.1
2 days
  • Feature@templatical/editor@templatical/renderer@templatical/template-tools@templatical/types

    Dividers can be a percentage of their column

  • Fix@templatical/import-beefree

    BeeFree imports keep divider widths, fonts and link colour

  • Fix@templatical/import-easy-email-pro

    Easy Email Pro imports keep text, merge tags, tables, raw HTML, headers and footers

  • Fix@templatical/import-html

    HTML import keeps divider widths, section backgrounds, cell padding, paragraph alignment and link underlines

  • Fix@templatical/import-topol

    Imported Topol buttons no longer paint their row in their fill colour

  • Fix@templatical/import-mjml

    MJML imports keep paragraph alignment, colour and size, and divider widths

  • Fix@templatical/import-stripo

    Stripo import keeps one section per row, divider widths, page and band colours, structure padding and plugin CSS

  • Fix@templatical/import-unlayer

    Unlayer imports keep divider widths, section colours and document settings

Read the full notes for 0.43.0
  • Fix@templatical/editor

    Palette clicks insert the block you asked for

  • Fix@templatical/template-tools

    Live notes survive a plain live reload. live reload --consume-annotations clears them after the working file was read. A note can name the block that contains its target, and the queue can be edited or deleted one note at a time.

  • Fix@templatical/editor

    Canvas and shadow-mount fixes

Read the full notes for 0.42.1
4 days
  • Feature@templatical/editor@templatical/renderer@templatical/template-tools@templatical/types

    Sections, images and buttons take a border, and corners can be rounded one at a time

  • Fix@templatical/editor@templatical/renderer@templatical/types

    Background fills can be transparent

Read the full notes for 0.42.0
  • Feature@templatical/editor@templatical/media-library

    Add Japanese editor and media library translations and localized recipient-facing content defaults.

Read the full notes for 0.41.0
  • Feature@templatical/core@templatical/editor@templatical/quality@templatical/renderer@templatical/types

    Add an embedder layout overlay: a Templatical JSON shell with one slot (top-level or inside a layout wrapper card), applied at preview and toMjml / toHtml, never written into getContent().

Read the full notes for 0.40.0

Showing the 20 most recent releases.

Every release

Looking for an older version?

The docs changelog carries the full history back to the first release, with the complete notes for every entry.