Skip to content

Auto-save not triggered when editing Portable Text block fields #1118

@adentdk

Description

@adentdk

Description

When editing fields inside a Portable Text block (e.g., changing a headline in a Hero block, updating an image in a CTA block), the auto-save mechanism does not fire. The editor does not detect the change as dirty.

However, if you then make any edit to the surrounding Portable Text content (e.g., add a <p> tag, type a space in a text block), auto-save fires and persists both the text change and the previously-undetected block field changes.

This suggests that block field edits don't propagate as TipTap document changes, so onUpdate never fires and isDirty remains false.

Steps to reproduce

  1. Open a content item that has a portableText field with custom blocks (e.g., a page with Hero, Feature, or CTA blocks)
  2. Click into a block and edit one of its fields (change a title, swap an image, toggle a setting)
  3. Wait for auto-save (2+ seconds of inactivity)
  4. Expected: Auto-save fires, "Saved" indicator appears
  5. Actual: Nothing happens. The editor does not detect the change. No save request is sent.

Workaround: Make any edit to the portable text content outside the block (add/remove a character in a paragraph). This triggers TipTap's onUpdate, which serializes the entire document including the modified block data, and auto-save fires normally.

Analysis

Based on reading ContentEditor.tsx:

  • Auto-save uses serializeEditorState() to compare currentData vs lastSavedData
  • isDirty only becomes true when the serialized form state changes
  • For portableText fields, changes propagate via TipTap's onUpdateonChangehandleFieldChangesetFormData
  • Block fields are rendered as custom TipTap node views. When their internal data (stored as node attributes) changes, TipTap may not consider this a document-level change — the node type, position, and structure haven't changed, only its attributes
  • Without onUpdate firing, the PortableTextEditor's onChange callback never executes, so formData never updates, isDirty stays false, and auto-save never triggers

Suggested fix

The block node view (or the field widget renderer inside it) should call editor.commands.updateAttributes() or dispatch a TipTap transaction when block field values change. This would make TipTap recognize the attribute change as a document update, triggering onUpdateonChange → auto-save.

Alternatively, block field changes could bypass TipTap entirely and directly call the parent handleFieldChange to update formData for the portable text field with the new serialized document.

Environment

  • EmDash version: 0.13.0
  • Astro adapter: @emdash-cms/cloudflare
  • Platform: Cloudflare Workers (local dev via wrangler/miniflare)
  • Browser: Chromium-based (reproducible across browsers)

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions