0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

フォーカスが外れる挙動を防ぎたくて

Posted at

何につまづいたか

Inputエリアに記述されたTextを範囲選択した際に、色変更などのメニュー画面を表示させたかった。
そのメニューのボタンをクリックした際、Inputエリアのフォーカスが外れてしまい、ユーザーに改めてInputエリアをクリックさせることになってしまった。
メニューのボタンをクリックしても元のInputの状態を維持できるようにしたかった。

どうやったのか?

  • onClickイベントではなくonMouseDown(or onPointerDown)を使用する
  • e.preventDefault()を使用してブラウザのデフォルト挙動を防いだ

コード例

import React, { useRef, useState } from "react";

const InputWithMenu = () => {
  const inputRef = useRef<HTMLInputElement>(null);
  const [showMenu, setShowMenu] = useState(false);

  const handleSelect = () => {
    // 選択範囲がある場合にメニューを表示
    const selection = window.getSelection();
    if (selection?.toString()) {
      setShowMenu(true);
    }
  };

  const handleMenuClick = (e: React.MouseEvent) => {
    e.preventDefault(); // Blur状態を防ぐ
    console.log("メニューのボタンがクリックされました");
  };

  return (
    <div style={{ position: "relative", padding: "20px" }}>
      <input
        ref={inputRef}
        type="text"
        placeholder="テキストを選択してください"
        onSelect={handleSelect}
        onBlur={() => setShowMenu(false)} // フォーカスが外れたらメニューを閉じる
      />

      {showMenu && (
        <div
          style={{
            position: "absolute",
            top: "50px",
            left: "10px",
            background: "lightgray",
            padding: "10px",
            borderRadius: "5px",
          }}
          onMouseDown={(e) => e.preventDefault()} // メニュークリック時にフォーカスを失わせない
        >
          <button onPointerDown={handleMenuClick}>色変更</button>
          <button onPointerDown={handleMenuClick}>削除</button>
        </div>
      )}
    </div>
  );
};

export default InputWithMenu;

なぜダメだったか?

onClickイベントのままhanldeMenuClickを使うと、ブラウザの挙動でクリックした対象にフォーカスが吸われてしまうので、コード例のinput要素の部分からフォーカスが外れてしまう。

これをonMouseDownに変更し、e.preventDefault()を実行することで、フォーカスを失わせない様にすることができる。

onMouseDownとonPointerDownの違い

コード例では、onMouseDownを使っているが、onPointerDownを使うこともできる。
それぞれの違いを以下の表に示す。

特徴 onMouseDown onPointerDown
対象デバイス マウスのみ マウス、タッチ、ペンすべて対応
ブラウザ互換性 古いブラウザでも完全対応 モダンブラウザで対応
ジェスチャー対応 ×
イベントの統一性 マウスに特化 複数デバイス間で統一的に動作

タッチ操作が必要なアプリケーションの場合は、onPointerDownを使用すると良い。

onBlurって?

onBlurは要素からフォーカスが外れた(失った)時に呼び出されるイベントハンドラー
その逆で、フォーカスが当たった時に呼び出されるイベントハンドラーはonFocus

onBlurはフォーカスが外れた時に呼び出されるので、例えば自動保存を行うときや入力内容の確認(例えば半角英数字のみか?)などの時に活躍する。

フォームの入力などを行う際、上手に使いこなして使い勝手の良いアプリを作れる様になりたい

最後に

onClick一辺倒でonPointerDownなどを知らなかったので、引き続き勉強しないと…です。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?