Skip to content

Feature request: IME composition event support for CJK input #942

@claudianus

Description

@claudianus

Problem

When typing CJK (Chinese/Japanese/Korean) characters in terminals like Kitty, pressing Enter to submit text often truncates the last composed character. This affects all TUI applications built with opentui that handle text input and submission.

Root Cause

Terminal protocols (particularly in Kitty, but also others) don't reliably report IME composition state through the standard keypress event stream. When the user presses Enter while an IME composition is in progress:

  1. The Enter keypress event fires immediately
  2. The IME composition commit event arrives after the Enter event
  3. TextareaRenderable.handleKeyPress() processes Enter → triggers submit
  4. The submitted text is missing the last character that was still in composition

Current Workaround

In opencode, we worked around this by double-deferring the submit handler:

onSubmit={() => {
  setTimeout(() => setTimeout(() => submit(), 0), 0)
}}

This gives the event loop 2 extra ticks for the IME commit to flush. It works but is fragile — the timing is not guaranteed, and it adds latency to every submit operation.

Requested Solution

Native IME composition support in opentui, such that:

  1. Composition start/update/end events are surfaced to renderables (similar to the browser compositionstart, compositionupdate, compositionend DOM events)
  2. TextareaRenderable buffers the composed text during composition and only commits it on compositionend
  3. Enter keypress during active composition commits the composition first, then triggers submit

This would eliminate the need for timing-based workarounds and provide reliable CJK input across all terminals.

Environment

  • opentui: v0.1.97 (as bundled in opencode)
  • Terminal: Kitty 0.42.1
  • OS: Linux
  • Affected languages: Korean (hangul), Japanese, Chinese

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreThis relates to the core packagefeatureNew feature or request

    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