1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IME入力確定以外のEnterキー入力を捕捉するにはbeforeinputを使うのが良さそう?

Last updated at Posted at 2025-11-05

Enter で送信、Shift+Enter のときは改行といった処理を行う際に、IME入力確定時のEnterとの区別が環境差異で大変だったのでまとめました。

前提

  • keydown で発火するイベント KeyboardEvent では、Enterキー押下時に .key プロパティの値が環境によって異なり、仮想キーを送信するWindows以外では、IME確定時にも Enter となるため判別困難
  • composition* イベントによるフラグ判定や、 KeyboardEvent.isComposing プロパティによってIME変換ステータスが検知できるはずだが、Safariでは他ブラウザと異なり compositionendkeydown の順に発火するため、 入力確定時は isComposing==false になる
  • KeyboardEvent.keyCode はWindows以外でも 229 となるため共通して判定に活用できるが、廃止プロパティであり非推奨
  • keypress イベントは文字入力を伴わないキー入力で発火しないため、IME確定では発火せずに改行入力でのEnterキー押下のみを捕捉できるが、廃止イベントであり非推奨

Enterキー押下を捕捉する

beforeinput で発火する InputEventイベントを用いたイベント捕捉を行います。
InputEvent.inputType により改行入力を検出することができます。
改行挿入時の inputType の値は環境及び入力対象によって異なるため、予め検討する必要がありますが、基本的には両方指定しておけば問題ないと思います。
ref: IME 入力 - ブラウザ間の違い

textArea.addEventListener('beforeinput', (e) => {
  const isLineBreak = e.inputType === 'insertLineBreak' || e.inputType === 'insertParagraph';
  if (isLineBreak) {
    e.preventdefault();
    console.log('Submit');
  }
});

修飾キーの状態を考慮する

InputEventKeyboardEvent と異なり、 .shiftKey プロパティ等で修飾キーの状態を検知することができません。
しかし、 composition* イベントと異なり、keydownbeforeinputinput の順であることがw3c仕様として定義されています。

https://w3c.github.io/uievents/split/keyboard-events.html#event-type-keydown
3.4.1. keydown
This event type MUST be dispatched before the beforeinput, input, and keyup events associated with the same key.

したがって、 keydown で修飾キーの状態を検査しておくことで beforeinput でもその状態を参照できます。

以下は、Shiftを押していないときの改行時に送信を行う例です。

let isShiftPressed = false;
textArea.addEventListener('keydown', (e) => {
  isShiftPressed = e.shiftKey;
});
textArea.addEventListener('beforeinput', (e) => {
  const isLineBreak = e.inputType === 'insertLineBreak' || e.inputType === 'insertParagraph';
  if (isLineBreak && !isShiftPressed) {
    e.preventdefault();
    console.log('Submit');
  }
});

Reactでの注意点

2025年11月現在、Reactではネイティブの beforeinput イベントに対応しておらず、 onBeforeInput を利用する場合、ポリフィルで TextEvent が発火するようになっています。

https://ja.react.dev/reference/react-dom/components/common
onBeforeInput: InputEvent ハンドラ関数。編集可能な要素の値が変更される前に発火します。React はまだネイティブの beforeinput イベントを使用しておらず、他のイベントを使用してポリフィルを試みます。

したがって beforeinput を使いたい場合は useEffect を使って手動でイベントリスナーを設定する必要があります。
その場合リスナーの重複登録を防ぐためクリーンアップする必要があります。

useEffect(() => {
  const textAreaElement = textAreaRef.current;
  if (!textAreaElement) return;

  let isShiftPressed = false;

  const handleKeyDown = (e: KeyboardEvent) => {
    isShiftPressed = e.shiftKey;
  };
  textAreaElement.addEventListener('keydown', handleKeyDown);

  const handleBeforeInput = (e: InputEvent) => {
    const isLineBreak =
      e.inputType === 'insertLineBreak' || e.inputType === 'insertParagraph';
    if (isLineBreak && !isShiftPressed) {
      e.preventDefault();
      console.log('Submit');
    }
  };
  textAreaElement.addEventListener('beforeinput', handleBeforeInput);

  return () => {
    textAreaElement.removeEventListener('keydown', handleKeyDown);
    textAreaElement.removeEventListener('beforeinput', handleBeforeInput);
  };
}, []);

おわりに

何か修正点や補足等あればコメントお願いします。

参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?