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

サンプルガイド
←サンプル一覧
nextjsrouting

Next.js で検索条件を保持したパンくずリストを生成する

カテゴリ・フィルタ・キーワードなどの現在の検索コンテキストをパンくず形式で表示し、各ステップをクリックして段階的に条件を外せる戻り導線パターン。

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

対応バージョン

nextjs 15react 19

前提環境

Next.js App Router の searchParams と URL クエリパラメータの基本を理解していること

概要

現在の検索条件(カテゴリ・難易度・キーワード)をパンくずリスト形式で表示し、各ステップをクリックするとその条件だけを外した URL に遷移できる戻り導線を実装する。Server Component で searchParams からパンくず項目を組み立て、<nav aria-label="breadcrumb"> でアクセシブルに実装する。

インストール

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

実装

パンくず項目の組み立て関数

// lib/breadcrumbs.ts

export type BreadcrumbItem = {
  label: string;
  href: string;
  isCurrent: boolean;
};

type FilterParams = {
  q?: string;
  framework?: string;
  category?: string;
  difficulty?: string;
};

const LABELS: Record<string, Record<string, string>> = {
  framework: { nextjs: "Next.js", react: "React" },
  category: {
    routing: "ルーティング",
    "search-filter": "検索 / フィルタ",
    testing: "テスト",
    styling: "スタイリング",
  },
  difficulty: {
    beginner: "初級",
    intermediate: "中級",
    advanced: "上級",
  },
};

/** 現在のフィルタ条件からパンくず項目を生成する */
export function buildBreadcrumbs(params: FilterParams): BreadcrumbItem[] {
  const items: BreadcrumbItem[] = [
    { label: "サンプル一覧", href: "/samples", isCurrent: false },
  ];

  const accumulated: string[] = [];

  for (const [key, value] of Object.entries(params)) {
    if (!value) continue;

    accumulated.push(`${key}=${encodeURIComponent(value)}`);
    const label = LABELS[key]?.[value] ?? value;

    items.push({
      label,
      href: `/samples?${accumulated.join("&")}`,
      isCurrent: false,
    });
  }

  if (items.length > 1) {
    items[items.length - 1] = {
      ...items[items.length - 1],
      isCurrent: true,
    };
  }

  return items;
}

パンくずコンポーネント

// components/SearchBreadcrumb.tsx
import Link from "next/link";
import type { BreadcrumbItem } from "@/lib/breadcrumbs";

type Props = {
  items: BreadcrumbItem[];
};

export function SearchBreadcrumb({ items }: Props) {
  if (items.length <= 1) return null;

  return (
    <nav aria-label="パンくずリスト">
      <ol className="flex flex-wrap items-center gap-1 text-sm text-gray-500">
        {items.map((item, i) => (
          <li key={item.href} className="flex items-center gap-1">
            {i > 0 && (
              <span aria-hidden="true" className="text-gray-300">
                /
              </span>
            )}
            {item.isCurrent ? (
              <span aria-current="page" className="font-medium text-gray-700">
                {item.label}
              </span>
            ) : (
              <Link href={item.href} className="hover:text-blue-600 hover:underline">
                {item.label}
              </Link>
            )}
          </li>
        ))}
      </ol>
    </nav>
  );
}

一覧ページで使う

// app/samples/page.tsx(抜粋)
import { buildBreadcrumbs } from "@/lib/breadcrumbs";
import { SearchBreadcrumb } from "@/components/SearchBreadcrumb";

export default async function SamplesPage({ searchParams }: Props) {
  const params = await searchParams;

  const q = typeof params.q === "string" ? params.q : undefined;
  const framework = typeof params.framework === "string" ? params.framework : undefined;
  const category = typeof params.category === "string" ? params.category : undefined;
  const difficulty = typeof params.difficulty === "string" ? params.difficulty : undefined;

  const breadcrumbs = buildBreadcrumbs({ framework, category, difficulty, q });

  return (
    <div>
      <SearchBreadcrumb items={breadcrumbs} />
      {/* ...一覧 */}
    </div>
  );
}

ポイント

  • buildBreadcrumbs は pure function として実装する。params だけを受け取るのでユニットテストが容易
  • 条件を1つずつ accumulated に積み上げることで、各パンくずステップが「その条件まで」を含む URL になる。クリックすると後続の条件が除去される
  • aria-current="page" を最後の項目(現在地)に付けることで、スクリーンリーダーがどこにいるかを伝えられる
  • <nav aria-label="パンくずリスト"> と <ol> を組み合わせることで、支援技術がパンくずナビゲーションとして認識できる
  • フィルタが何も適用されていない場合(items.length <= 1)はパンくずを表示しない。「サンプル一覧」だけのパンくずは冗長なため非表示にする
  • LABELS マップで URL パラメータ値を日本語ラベルに変換する。未登録の値はそのまま表示するフォールバックで、taxonomy 追加なしに動作する

注意点

nextjs-query-preserve-link は検索条件をそのまま保持して遷移するリンク生成。これは現在の検索コンテキストをパンくず形式で段階表示し、各ステップで条件を除去しながら戻れる導線パターンに特化。

関連サンプル

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

  • Next.js で現在の検索条件を保持したままページ遷移するリンクを生成する

    一覧ページの検索語・フィルタ・sort・page を URL クエリとして保持し、詳細ページや別導線へ遷移後に戻ったとき条件が復元されるリンク生成パターン。

  • Next.js で URL クエリパラメータのフィルタを一括リセットする

    複数の URL クエリパラメータ(q・category・status など)をまとめて削除してフィルタ状態を初期化するパターン。リセットボタンと個別削除の両方を実装する例。

  • Next.js の searchParams で URL 同期フィルタを実装する

    searchParams を読み取り、URL クエリパラメータに基づいてサーバー側でリストをフィルタリングする実装例。

  • Jest で URLSearchParams を使った URL クエリ変換ロジックをテストする

    URLSearchParams を操作するフィルタクエリ生成・パース関数を Jest でユニットテストする例。jsdom 環境での URLSearchParams の挙動とエッジケースの検証パターン。

  • Next.js で認証状態に応じてページを redirect する

    Server Component や Route Handler でセッションの有無を確認し、認証済みユーザーをダッシュボードへ、未認証ユーザーをログインページへ redirect するパターンの例。

関連仕様

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

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