Skip to content

TUI: cannot submit a custom "Type your own answer" in question/ask prompt (Enter swallowed by focused textarea) #30393

Description

@kristianvast

Summary

In the interactive TUI, when a question (the askuserquestion tool / question.asked flow) offers a "Type your own answer" option, the typed custom answer cannot be submitted. Pressing Enter after typing does nothing — it only inserts newlines into the input box. Selecting one of the predefined options works fine; only the custom free-text path is broken.

Environment

  • opencode v1.15.13 (latest release at time of filing)
  • Linux x86-64, terminal: kitty
  • Reproducible regardless of model/agent — it's a TUI input-handling issue.

Steps to reproduce

  1. In an interactive opencode TUI session, trigger any question that allows a custom answer (custom defaults to true), so the dialog shows numbered options plus a final "Type your own answer" row.
  2. Select "Type your own answer" (it enters edit mode and focuses the text input).
  3. Type some text.
  4. Press Enter to confirm/submit.

Expected

The typed text is submitted as the answer (question.reply), the same way pressing Enter on a predefined option submits it.

Actual

Enter does nothing except add blank lines in the input box. There is no way to confirm/send the custom answer (and no mouse "submit" affordance either). The only escape is Esc to dismiss the question entirely.

Root cause

In the interactive TUI question component, packages/opencode/src/cli/cmd/tui/routes/session/question.tsx (QuestionPrompt):

  • Choosing "Type your own answer" sets store.editing = true and focuses an @opentui/core <textarea> (via val.focus() in the ref).
  • Submission of the typed answer is wired only through the declarative keymap:
useBindings(() => ({
  mode: QUESTION_MODE,
  enabled: store.editing && !confirm(),
  bindings: [
    // ...
    { key: "return", desc: "Submit answer edit", cmd: () => { /* pick(text, true) -> question.reply */ } },
  ],
}))

A focused textarea consumes the Enter keypress itself (newline insertion, up to maxHeight={6}), so the key never reaches the useBindings keymap and the return -> submit binding never fires.

Proof that it's key delivery, not the submit logic: if the binding fired, pick(text, true) would immediately call sdk.client.question.reply(...). It doesn't submit, so the binding is never reached. The only difference between the working option-selection path and the broken custom path is the focused textarea capturing the key.

Why predefined options work but custom doesn't

  • Selecting an option: no textarea is focused, so Enter / number keys flow into the other useBindings block (enabled: !store.editing) and submit normally.
  • Typing a custom answer: the focused textarea swallows Enter before the keymap sees it.

In-repo reference implementation that handles this correctly

The direct-mode footer question UI, packages/opencode/src/cli/cmd/run/footer.question.tsx (RunQuestionBody), handles the identical flow correctly by using a global imperative keyboard handler and explicitly preventing default while editing:

useKeyboard((event) => {
  // ...
  if (cur.editing) {
    if (event.name === "escape") { /* cancel */ return }
    if (event.name === "return" && !event.shift && !event.ctrl && !event.meta) {
      saveCustom()
      event.preventDefault() // stops the focused textarea from eating Enter
    }
    return
  }
  // ...
})

That event.preventDefault() is exactly what the interactive TUI QuestionPrompt is missing.

Suggested fix

Mirror the footer's approach in QuestionPrompt (tui/routes/session/question.tsx): while store.editing is true, intercept Enter at a level that runs before the focused textarea (e.g. a useKeyboard handler), invoke the existing submit logic, and call event.preventDefault(). Reserve Shift+Enter for inserting a newline. The submit logic itself is already present and correct — only key delivery to it is broken.

Notes

  • No existing issue found for this when searching the tracker (custom answer / type your own answer / question submit).
  • Affects the latest release (v1.15.13); the same textarea pattern appears to still be present on main, so this is not fixed by updating.

Permalinks (v1.15.13)

Metadata

Metadata

Assignees

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