Skip to content

Keep a contenteditable's edits after it loses focus - #212

Merged
joeldrapper merged 7 commits into
mainfrom
claude/preserve-contenteditable-oanz4c
Oct 13, 2026
Merged

joeldrapper merged 7 commits into
mainfrom
claude/preserve-contenteditable-oanz4c

Conversation

@joeldrapper

Copy link
Copy Markdown
Collaborator

Requested by Joel · project thread

Before: with preserveChanges, a contenteditable only kept what the user typed while it was focused. Typing a note and then clicking a Save button blurs the editor, so the morph that follows reset the note to the server's markup.

After: a contenteditable the user edited keeps its content under preserveChanges, focused or not, just like a typed input keeps its value. Untouched editors, and editors changed only by script, still follow the markup, and morphlex-clobber still lets the server replace an edited one.

The browser keeps no dirty flag for contenteditable, so morphlex now adds one capturing input listener to the document when it loads and notes the editing hosts that get an input event (the first node of its composed path, so editors in shadow roots count). Joel picked this over keeping every editor.

How: visitChildNodes already pins the children of the focused editor. It now also pins them when the element is, or is inside, a noted editing host that's still isContentEditable. The check is skipped entirely until the first input event.

Known limit, shared with the existing focused-editor behaviour: the editor's old content isn't known, so among identical unkeyed sibling editors an untouched one can take the edited one's target and the two swap places (content is kept either way). An id avoids it.

Benchmark vs main (perf-sweep harness, Chromium, 15 rounds): all scenarios within noise, from -11% to +5%.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59


Generated by Claude Code

With preserveChanges, an editing host the user edited keeps its children,
like a focused one. The browser keeps no dirty flag for contenteditable, so
an input listener on the document notes the editing hosts the user edits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
@joeldrapper joeldrapper self-assigned this Oct 13, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T09:14:42.127873Z 059077c New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Firefox types after the last element when the caret follows it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb8bda6bc7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts
Comment thread src/morphlex.ts
Comment thread src/morphlex.ts Outdated
Comment thread src/morphlex.ts Outdated
isContentEditable throws for SVG and MathML elements, which a preserving
morph visits once any edit was seen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a27f8383d7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts Outdated
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 750ed8b2b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts Outdated
Comment thread src/morphlex.ts Outdated
document,
"input",
(event) => {
if (!event.isTrusted) return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish trusted scripted edits from user input

In browsers implementing editing commands, application code such as document.execCommand("insertText", false, value) generates an input event whose isTrusted value is true, so this guard marks a script-modified editor and later prevents server markup from replacing it. Unlike the already-covered dispatchEvent case, the fresh evidence is that the execCommand algorithm explicitly creates a trusted input event; therefore trust alone does not establish that the user edited the content.

AGENTS.md reference: AGENTS.md:L31-L31

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this as is. In practice, execCommand runs because of a user action, like a rich-text toolbar's bold button or a paste handler, and those edits are the user's too, so keeping them is what we want. An app that rewrites an editor through execCommand without the user asking, and then expects server markup to replace that, is unusual. morphlex-clobber covers it.


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59311e8b12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts Outdated
Form controls also get trusted input events, and keep their own record of
the user's changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
@joeldrapper
joeldrapper added this pull request to stack #213 October 13, 2026 08:54
@joeldrapper joeldrapper mentioned this pull request Oct 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db806455ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts
Comment thread src/morphlex.ts
A form control inside an editor inherits isContentEditable but isn't an
editing host. Elements inside an editor no longer each walk up to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 059077ca41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/morphlex.ts
Comment thread src/morphlex.ts
@joeldrapper
joeldrapper merged commit ae7ab17 into main Oct 13, 2026
7 checks passed
@joeldrapper
joeldrapper deleted the claude/preserve-contenteditable-oanz4c branch October 13, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants