Skip to content

fix: keep the trailing newline placeholder in the composition input - #2041

Merged
Bilb merged 1 commit into
session-foundation:devfrom
Belinus-code:fix/composition-trailing-newline-backspace
Oct 26, 2026
Merged

Bilb merged 1 commit into
session-foundation:devfrom
Belinus-code:fix/composition-trailing-newline-backspace

Conversation

@Belinus-code

Copy link
Copy Markdown
Contributor

First time contributor checklist:

Contributor checklist:

  • My commits are in nice logical chunks with good commit messages
  • My changes are rebased on the latest dev branch
  • A pnpm ready run passes successfully (I ran prettier --check, eslint on the changed file and tsc --noEmit, all clean; I did not run the full pnpm test)
  • My changes are ready to be shipped to users

Description

Fixes #2040.

When the last line of the composition input becomes empty (for example by pressing backspace on the only character of that line, or on the first character of a trailing line after lines were added with ctrl+enter), the line seemed to be deleted and the caret jumped to the end of the previous line.

Cause: in that case Chromium inserts a trailing <br> as a placeholder so the empty last line stays rendered. handleChange() in CompositionInput.tsx removed every <br>. What remained was a text ending in a single \n without a placeholder, which white-space: pre-wrap does not render as an empty line.

Fix: a trailing <br> that follows a text node ending in \n is now replaced by a \n text node instead of being deleted. This is the same placeholder Chromium already inserts when pressing enter at the end of the input (the draft then ends in \n\n, which is why sending trims trailing newlines). Any other <br> is still removed.

Testing:

  • Manual: dev build of the app, typed several lines (aaa, newline, b, newline, c) and pressed backspace on the last line. Before the fix the empty line vanished and the caret jumped up (confirmed with debug logging: onInput saw "…\n<br>" and handleChange removed the <br>). After the fix the empty line stays and the caret stays on it.
  • No new automated test: the behaviour depends on Chromium's contenteditable DOM and lives inside the component, which the existing unit tests do not cover.
  • OS: tested on Ubuntu 24.04 (WSL2 with WSLg), Electron 40 as pinned in this repo. The issue was reported on Windows 10; I could not run a Windows build locally, so a check on Windows would be welcome.

When the last line of the composition input becomes empty (for example
after pressing backspace on the only character of that line), Chromium
inserts a trailing <br> as a placeholder so the empty line stays
rendered. handleChange() removed every <br>, which left a text ending in
a single "\n" with no placeholder. With white-space: pre-wrap such a
trailing newline is not rendered as an empty line, so the line seemed to
be deleted and the caret jumped to the end of the previous line.

Replace a trailing <br> that follows a text node ending in "\n" with a
"\n" text node instead of deleting it. This is the same placeholder
Chromium already inserts when pressing enter at the end of the input
(the draft then ends in "\n\n"). Any other <br> is still removed.

Fixes session-foundation#2040

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@Bilb
Bilb merged commit 2bb37b4 into session-foundation:dev Oct 26, 2026
11 checks passed
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.

[BUG] Backspace on first character of a line deletes newline / collapses block

2 participants