Skip to content

Prompt input should be able to treat only Ctrl + Enter as submit command (and make it opt-out for Japanese users) #400

@tats-u

Description

@tats-u

Problem

Currently, <PromptInputTextarea /> hardcodes Enter as the submit shortcut and Shift+Enter as the newline shortcut (source). While there is an isComposing guard that prevents submission during active IME composition, the bare Enter key immediately after IME commit still triggers submission, causing frequent accidental submissions for CJK language users — sometimes colloquially called gobaku (誤爆) in Japanese.

Real-world precedent: Microsoft Teams

Microsoft Teams recently rolled out an option to switch the Enter key behavior (Enter = send → Enter = newline, Ctrl+Enter = send) in February–March 2026. This change was widely celebrated in Japan (Togetter discussion, Japanese), where accidental submissions due to IME usage had been a long-standing frustration. This validates the strong user demand for this feature in chat-style input components.

Real-world precedent 2: GitHub Copilot Coding Agent

The initial prompt input of GitHub Copilot Coding Agent (https://github.com/copilot/agents) treats Enter as a line break instead of submit. You need to press Ctrl + Enter to start a Coding Agent session.

Who is affected (severity by language)

Language Severity Reason
🇯🇵 Japanese Critical Enter is heavily used for conversion confirmation (変換確定). Users routinely press Enter multiple times in quick succession. One extra press → accidental submit.
🇹🇼 Traditional Chinese (Taiwan) High The Bopomofo (Zhuyin / 注音) input method uses Enter to confirm character selection (上屏). This is a well-known source of accidental message sending (誤傳/誤發送) in chat applications in Traditional Chinese communities.
🇭🇰🇲🇴 Traditional Chinese (Hong Kong / Macau) Moderate Both Cangjie (倉頡) and Sucheng (速成) input methods can use Enter for committing text (上屏), although Space and number keys are the primary confirmation keys.
🇨🇳 Simplified Chinese Moderate Pinyin (拼音) IMEs can use Enter for committing text (上屏), although Space is the primary confirmation key. Wubi (五笔) also predominantly uses Space for the first candidate, with Enter for selecting non-first candidates or special operations. Accidental sends from Enter are a recognized issue with Chinese IMEs as well. However, Chinese users are generally accustomed to Enter-to-send from dominant chat platforms (WeChat/微信, QQ default to Enter = send), so this should not be the default for zh locales.
🇰🇷 Korean Low–Moderate Hangul auto-commits character-by-character in real-time for most typing. However, Hanja (한자/漢字; substantially same as han/kanji in Chinese/Japanese but rarely used in South (and North) Korea these days) conversion requires pressing Enter to confirm the selected character (확정), which can trigger accidental sends (오전송) in the same way as Japanese/Chinese IMEs. Hanja is
Latin/others Minimal No IME composition involved.

Why this matters now

With high-cost "thinking" models like GPT-5.x Pro and Claude Opus 4.x, prompts tend to be long and carefully crafted. An accidental mid-composition submission wastes both tokens (= money) and the user's time, as partial prompts produce poor or useless results. The cost of an accidental submit is no longer negligible.

Proposed Solution

1. Add a submitMode prop to <PromptInput /> or <PromptInputTextarea />

type SubmitMode = "enter" | "mod-enter";

// Usage
<PromptInput submitMode="mod-enter" onSubmit={handleSubmit}>
  ...
</PromptInput>
submitMode Submit New line
"enter" (default, current behavior) Enter Shift+Enter
"mod-enter" Ctrl+Enter (or Cmd+Enter on macOS) Enter

2. Smart default based on user's language

Applications building on top of AI Elements should be able to detect the user's language and set a sensible default:

  • SSR: Parse the Accept-Language request header
  • CSR-only: Use navigator.language / navigator.languages

Recommended defaults:

Language tag prefix Default submitMode
ja "mod-enter"
All others "enter"

Note

Despite Traditional/Simplified Chinese users also using IMEs with Enter confirmation, Chinese (especially Simplified) users are considered to be culturally accustomed to Enter-to-send from dominant chat platforms (WeChat, QQ). Defaulting to "mod-enter" for zh would likely feel unnatural. (feedback by natives are highly encouraged) Individual app developers can override this as they see fit.

3. Persistence (guidance for consumers)

The component library itself doesn't need to handle persistence, but documentation should recommend:

  • Store the user's preference in localStorage (CSR), cookies (SSR), or a database (authenticated users)
  • Provide a settings UI toggle (e.g., a checkbox: "Press Ctrl+Enter to send")

Implementation notes

The key change is in PromptInputTextarea's handleKeyDown (packages/elements/src/prompt-input.tsx L969–L997):

// Current behavior (simplified):
if (e.key === "Enter") {
  if (isComposing || e.nativeEvent.isComposing) return;
  if (e.shiftKey) return; // newline
  e.preventDefault();
  form?.requestSubmit();
}

// Proposed (simplified):
if (e.key === "Enter") {
  if (isComposing || e.nativeEvent.isComposing) return;

  if (submitMode === "mod-enter") {
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault();
      form?.requestSubmit();
    }
    // Otherwise, let Enter insert a newline naturally
  } else {
    // Current "enter" mode
    if (e.shiftKey) return;
    e.preventDefault();
    form?.requestSubmit();
  }
}

Additional considerations

  • The submit button tooltip / hint text should update dynamically (e.g., show ⌘↵, ^↵, or Ctrl+↵ instead of when in mod-enter mode)
  • Tests already exist for IME composition guard ("does not submit on Enter during IME composition - #21"); new tests should cover the mod-enter mode
  • Mobile: On mobile devices, Ctrl+Enter is not practical. Consider keeping Enter-to-send on mobile regardless of setting, or relying on the send button (<PromptInputSubmit />) as the primary mobile submission method (which already exists)

Existing prior art

References

Related

Notice: Claude Opus 4.6 is used to refine the text

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions