fix: treat Option+Return as newline in multiline text inputs (#118)

* fix: treat Option+Return as newline in multiline text inputs

Currently only Shift+Return inserts a newline in multiline text areas
(like the chat input). Option+Return (Alt+Return) was treated the same
as plain Return, triggering the send action.

Add altKey checks alongside the existing shiftKey checks in both:
- ChatInput: skip send when altKey is held
- PromptInputTextarea: early-return (allow newline) when altKey is held

* test: add alt-enter multiline regression coverage
This commit is contained in:
Matt Toohey
2026-04-08 15:06:39 +10:00
committed by GitHub
parent 5b8aebdde2
commit 08106b67ef
4 changed files with 53 additions and 3 deletions
+1 -1
View File
@@ -279,7 +279,7 @@ export function ChatInput({
}
}
}
if (e.key === "Enter" && !e.shiftKey) {
if (e.key === "Enter" && !e.shiftKey && !e.altKey) {
e.preventDefault();
handleSend();
}
@@ -1,5 +1,5 @@
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { useState } from "react";
import { ChatInput } from "../ChatInput";
@@ -75,6 +75,23 @@ describe("ChatInput", () => {
expect(onSend).not.toHaveBeenCalled();
});
it("does not call onSend on Alt+Enter (newline)", async () => {
const onSend = vi.fn();
const user = userEvent.setup();
render(<ChatInput onSend={onSend} />);
const input = screen.getByRole("textbox");
await user.type(input, "hello");
const wasNotPrevented = fireEvent.keyDown(input, {
altKey: true,
key: "Enter",
});
expect(wasNotPrevented).toBe(true);
expect(onSend).not.toHaveBeenCalled();
expect(input).toHaveValue("hello");
});
it("shows current model name in model picker", () => {
render(
<ChatInput
@@ -0,0 +1,33 @@
import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import {
PromptInput,
PromptInputSubmit,
PromptInputTextarea,
} from "./prompt-input";
describe("PromptInputTextarea", () => {
it("does not submit on Alt+Enter and inserts a newline", async () => {
const onSubmit = vi.fn();
const user = userEvent.setup();
render(
<PromptInput onSubmit={onSubmit}>
<PromptInputTextarea />
<PromptInputSubmit />
</PromptInput>,
);
const input = screen.getByRole("textbox");
await user.type(input, "hello");
const wasNotPrevented = fireEvent.keyDown(input, {
altKey: true,
key: "Enter",
});
expect(wasNotPrevented).toBe(true);
expect(onSubmit).not.toHaveBeenCalled();
expect(input).toHaveValue("hello");
});
});
@@ -972,7 +972,7 @@ export const PromptInputTextarea = ({
if (isComposing || e.nativeEvent.isComposing) {
return;
}
if (e.shiftKey) {
if (e.shiftKey || e.altKey) {
return;
}
e.preventDefault();