Skip to content

[Bug]: Dead-key apostrophe inserts extra quotes in the composer #16859

Closed

Description

@ElieSauveterre

Area

apps/web, including the Linux desktop composer.

Steps to reproduce

  1. Use a keyboard layout where the apostrophe key is a dead key for accents.
  2. Type s in the composer with the caret at the end and no selected text.
  3. Press the single-quote key once, then Space to commit a literal apostrophe.
  4. Type il.

Expected behavior

The composer contains s' after step 3 and s'il after step 4. Accented letters should continue to compose normally.

Actual behavior

The composer contains s'´' after step 3, then s'il' after step 4. Accented letters work normally; committing an apostrophe is the broken case.

Impact

Frequent incorrect text when writing French with a dead-key keyboard layout.

Version and environment

Linux x64 desktop, 0.0.46-nightly.20261007.2774, also present in main at 611132c171f3a821bd2e32f22261135cef6330ac.

Investigation

The composer's handleTextInput treats any nonempty replacement range as selected text to surround with delimiters. ProseMirror can report a replacement range covering a provisional dead-key accent while the current editor selection is empty. Surrounding that accent with ' produces exactly s'´', then selects the accent so subsequent typing leaves a trailing apostrophe.

A focused test mounting the actual controlled ComposerPromptEditorTiptap in jsdom reproduces s'´' in both plain and rich-text modes when replaying this replacement. This is a replay of the editor's text-input boundary, not a native Linux keyboard-event capture.

Existing issues and PRs were searched for a duplicate. This report is specifically about committing a literal apostrophe, rather than accent composition or Markdown grave accents.

Activity

  1. juliusmarminge commented on Oct 7, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the clear report. This is a confirmed bug on current main.

    Root cause
    handleTextInput in apps/web/src/components/ComposerPromptEditorTiptap.tsx (~L1020–1045) wraps text in a delimiter pair whenever the typed character is in SURROUND_CLOSE (L178, which includes ', `, ") and the replacement range is non-empty (if (!closer || from === to) return false;, L1023). It never checks view.composing or view.state.selection. With a dead-key layout (e.g. US-International), ProseMirror passes a range covering the provisional accent even though the selection is empty, so the accent gets "wrapped" ('´') instead of being replaced. That's what produces s'´' and then s'il'.

    Fix
    Only surround when the user actually has a selection: bail out early if view.composing is true, or if view.state.selection is empty, isn't a TextSelection, or doesn't match from/to. Otherwise return false so native composition can finish.

    Prior work
    #12644 (@SpizzyCoder) added exactly this guard but was closed unmerged because it had no verification recording, which CONTRIBUTING.md requires. As @adolago noted there, this has affected US-International users since v0.0.43 (#12160). A new PR with this guard is welcome. Please include a before/after recording that shows quote + Space, quote + vowel, and wrapping an explicit selection on a dead-key layout. Related: #3142 (dead-key backtick for inline code, still open).

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions