1
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

はじめに

Webアプリケーションでよく見かける「追加」ボタンを押して新しいフォームを作成する機能。
ユーザーは追加後、すぐに入力を始めたいはずです。しかし、マウスやTabキーで入力欄を選択するのは手間がかかります。

この記事では、フォームを追加したら自動的に入力欄にフォーカスが移動する機能の実装方法を紹介します。

修正前(フォーカスが当たらないためフォームの入力が難しい)
758965121.542858.gif

修正後(フォーカスが当たるためフォームの入力が簡単)
758965121.614779.gif

こんな課題を解決します

  • フォームを追加したら、マウス操作なしですぐに入力を始めたい
  • 画面が自動でスクロールして、追加したフォームが見えるようにしたい

実装のステップ

1. 基本的な準備

まずはフォーム要素を管理するための基本的な実装から始めます

const FormListExample = () => {
  // フォームのリストを管理(各フォームにユニークなIDを付与)
  const [forms, setForms] = useState([{ id: crypto.randomUUID() }]);
  
  // DOM要素への参照を保持
  const formsRef = useRef({});
  // 要素数の変化を検知するための参照
  const formsLengthRef = useRef(forms.length);

  // ...他の実装
};

2. 要素への参照を管理

フォーカスを制御するには、DOM要素への参照が必要です

// 要素への参照を管理するための関数
const setFormRef = useCallback((id, node) => {
  if (node) {
    formsRef.current[id] = node;
  } else {
    delete formsRef.current[id];
  }
}, []);

3. フォーム追加時のフォーカス制御

フォームが追加されたときの処理を実装します

useEffect(() => {
  // 初回レンダリング時は処理をスキップ
  if (formsLengthRef.current === 0) {
    formsLengthRef.current = forms.length;
    return;
  }

  // フォームが追加された場合
  if (forms.length > formsLengthRef.current) {
    const lastId = forms[forms.length - 1].id;
    const lastElement = formsRef.current[lastId];
    
    if (lastElement) {
      // 追加されたフォームが見えるようにスクロール
      lastElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
      
      // 最初の入力欄にフォーカスを設定
      const input = lastElement.querySelector('input, select, textarea');
      if (input instanceof HTMLElement) {
        input.focus();
      }
    }
  }

  // 現在の要素数を更新
  formsLengthRef.current = forms.length;
}, [forms]);

実装のポイント解説

1. なぜ参照(ref)を使うのか

  • DOM要素への直接アクセスが必要
  • 状態更新による再レンダリングに影響されない
  • 要素の追加に柔軟に対応できる

2. フォーカス制御のコツ

  • querySelectorで適切な入力要素を選択
  • 複数の入力欄がある場合は、最初の要素を選択
  • スクロール後にフォーカスを設定することで、視認性を確保

3. スクロール制御のポイント

  • scrollIntoViewのオプション設定が重要
    • behavior: 'smooth'でスムーズなスクロール
    • block: 'center'で要素を中央に表示

まとめ

とても使いやすくなったと思います。
些細な部分ではありますが、このような部分もこだわった機能を実装していくことがよりユーザーファーストなサービスを作成する意識が芽生えると思っています。
引き続き頑張ります!

1
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
1
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?