© TOOLS BOX — Next.js / React / TypeScript コードサンプル集

サンプルガイド
←サンプル一覧
nextjssearch-filter

React で検索入力欄にキーボードショートカットでフォーカスする

/ や Ctrl+K などのキーボードショートカットで検索入力欄へフォーカスを移動するパターン。useEffect と keydown イベントで実装し、入力中の誤作動を防ぐ制御も示す。

難易度: 初級·更新: 2026-04-18

対応バージョン

nextjs 15react 19

前提環境

React の useRef と useEffect の基本を理解していること

概要

/ キーや Ctrl+K で検索入力欄へフォーカスを移動するショートカットを実装する。useEffect でグローバルな keydown イベントをリッスンし、input や textarea に入力中のときは誤作動しないよう制御する。

インストール

# 追加インストールは不要

実装

ショートカットフック

// hooks/useSearchShortcut.ts
import { useEffect } from "react";

type Options = {
  /** フォーカス先の input の ref */
  inputRef: React.RefObject<HTMLInputElement | null>;
  /** "/" キーを有効にするか(デフォルト true) */
  enableSlash?: boolean;
  /** Ctrl+K / Cmd+K を有効にするか(デフォルト true) */
  enableCtrlK?: boolean;
};

export function useSearchShortcut({
  inputRef,
  enableSlash = true,
  enableCtrlK = true,
}: Options) {
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement;

      // input / textarea / contenteditable に入力中は無視
      if (
        target.tagName === "INPUT" ||
        target.tagName === "TEXTAREA" ||
        target.isContentEditable
      ) {
        return;
      }

      const isSlash = enableSlash && e.key === "/";
      const isCtrlK = enableCtrlK && (e.ctrlKey || e.metaKey) && e.key === "k";

      if (isSlash || isCtrlK) {
        e.preventDefault();
        inputRef.current?.focus();
        inputRef.current?.select();
      }
    };

    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [inputRef, enableSlash, enableCtrlK]);
}

検索インプットへの適用

// components/SearchInput.tsx
"use client";

import { useRef } from "react";
import { useSearchShortcut } from "@/hooks/useSearchShortcut";

type Props = {
  value: string;
  onChange: (v: string) => void;
  placeholder?: string;
};

export function SearchInput({ value, onChange, placeholder = "検索…" }: Props) {
  const inputRef = useRef<HTMLInputElement>(null);
  useSearchShortcut({ inputRef });

  return (
    <div className="relative">
      <input
        ref={inputRef}
        type="search"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        className="w-full rounded border border-gray-200 py-2 pl-3 pr-20 text-sm focus:outline-none focus:ring-1 focus:ring-blue-400"
        aria-label="サンプルを検索"
      />
      {/* ショートカットヒント */}
      <span
        className="pointer-events-none absolute inset-y-0 right-2 flex items-center gap-1 text-xs text-gray-400"
        aria-hidden="true"
      >
        <kbd className="rounded border border-gray-200 px-1">/</kbd>
      </span>
    </div>
  );
}

Ctrl+K のみ有効にする場合

// Ctrl+K / Cmd+K のみ("/" は無効)
useSearchShortcut({ inputRef, enableSlash: false, enableCtrlK: true });

フォーカス後にモーダルを開くパターン

// hooks/useCommandPaletteShortcut.ts
import { useEffect } from "react";

export function useCommandPaletteShortcut(onOpen: () => void) {
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "k") {
        e.preventDefault();
        onOpen();
      }
    };
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [onOpen]);
}

ポイント

  • target.tagName === "INPUT" チェックで、ユーザーが別の入力欄を使っているときに誤フォーカスしないよう防ぐ。contenteditable も合わせてチェックする
  • e.preventDefault() を呼ぶことで / キーが入力欄に入力されるのを防ぐ。フォーカス移動のみを行う
  • inputRef.current?.select() でフォーカスと同時に既存の入力値を全選択する。上書き入力がしやすくなる
  • useEffect のクリーンアップで removeEventListener を確実に呼ぶ。コンポーネントのアンマウント後にハンドラが残るメモリリークを防ぐ
  • enableSlash / enableCtrlK のオプションで、プロジェクトの UX 方針に合わせてショートカットを選べる設計にする
  • Ctrl+K は macOS では Cmd+K として metaKey になるため、e.ctrlKey || e.metaKey で両方チェックする

注意点

react-clear-search-button は入力値のクリア操作。nextjs-url-filter-reset は URL フィルタのリセット。これはキーボードショートカットで検索入力欄へフォーカスを移動する入力導線の改善パターンに特化。

関連サンプル

同じテーマや技術スタックを使った実装例

  • React で検索入力欄にクリアボタンを追加する

    検索フィールドに入力内容を一発でクリアする × ボタンを追加し、入力中だけ表示する制御と URL クエリへの反映パターンを示す例。

  • React で検索キーワードに応じた 0 件 EmptyState を表示する

    検索語の有無・フィルタ条件の有無によって異なる 0 件メッセージを出し分け、クリアボタンや別キーワード提案など検索導線につながる EmptyState を実装する例。

  • React で検索結果が 0 件のときに関連キーワードを提案する

    検索結果が 0 件のとき、入力キーワードに近い候補を提案して検索のやり直しを促す UX パターン。部分一致による候補抽出とワンクリック再検索の実装例。

  • React でコマンドパレット風のキーワードフィルタ UI を実装する

    キーボードショートカットで開くモーダル内で候補リストをリアルタイムフィルタし、キーボードナビゲーションで選択するコマンドパレット UI の実装例。

  • React で検索キーワードにマッチした文字列をハイライト表示する

    入力された検索語と一致するテキスト部分を分割して <mark> タグや span で強調表示するコンポーネントの実装例。

関連仕様

このサンプルを理解するのに役立つ仕様や概念

  • FrameworkNext.jsReact ベースのフルスタックフレームワーク。SSR・SSG・App Router・API Routes を提供する。
←サンプル一覧に戻る