React useRefで入力欄にフォーカスを当てる
入力フォームを開いた直後や、入力エラーが出たときに、特定の入力欄へフォーカスしたいことがあります。DOMの要素自体を参照するにはuseRefを使います。
入力欄を参照する
import { useRef, useState } from 'react';
export const ItemForm = () => {
const inputRef = useRef<HTMLInputElement>(null);
const [name, setName] = useState('');
const [message, setMessage] = useState('');
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!name.trim()) {
setMessage('名前を入力してください。');
inputRef.current?.focus();
return;
}
setMessage(`追加しました: ${name.trim()}`);
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="item-name">名前</label>
<input
id="item-name"
ref={inputRef}
value={name}
onChange={(event) => setName(event.target.value)}
aria-describedby="item-message"
/>
<button type="submit">追加</button>
<p id="item-message" role="status">{message}</p>
</form>
);
};currentは初回描画中などにnullになり得るので、?.focus()で確認します。ボタンを押して空欄なら、メッセージを表示し、入力欄へフォーカスが戻ります。
stateとrefの違い
入力値は画面表示に使うためuseStateで管理します。一方、DOMへの参照は描画内容そのものではないためuseRefに置きます。ref.currentを書き換えても再描画は起きません。
表示後にフォーカスしたい場合
条件付きで入力欄を表示する場合、表示する前にfocus()しても対象要素はありません。表示後にEffectを実行するか、用途に合えばautoFocusを検討します。モーダルではフォーカスを開く前の要素へ戻すことも含めて設計してください。
ページ読み込み直後に意図せずフォーカスを移すと、キーボード操作やスクリーンリーダーの利用者を混乱させることがあります。明確な操作の結果として必要な場合に使います。