Menu

<Form>

<Form> コンポーネントは、HTML <form> 要素を拡張し、プリフェッチローディングUIクライアント側のナビゲーションプログレッシブエンハンスメントを提供します。

URLのsearchパラメータを更新するフォームに役立ち、これらを実現するために必要な定型コードを削減します。

基本的な使用方法:

/app/ui/search.js
TypeScript
import Form from 'next/form'
 
export default function Page() {
  return (
    <Form action="/search">
      {/* 送信時に、入力値がURLに追加されます。
          例: /search?query=abc */}
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  )
}

リファレンス

<Form> コンポーネントの動作は、action プロップが文字列か関数かによって異なります。

  • action文字列の場合、<Form>GET メソッドを使用するネイティブHTMLフォームのように動作します。フォームデータはsearchパラメータとしてURLにエンコードされ、フォーム送信時に指定されたURLにナビゲーションします。さらに、Next.jsは以下を行います:
    • フォームが表示されるとプリフェッチし、共有UI(例:layout.jsloading.js)をプリロードし、より高速なナビゲーションを実現します。
    • フォーム送信時に、フルページリロードではなくクライアント側のナビゲーションを実行します。これにより、共有UIとクライアント側の状態が保持されます。
  • action関数(サーバーアクション)の場合、<Form>Reactフォームのように動作し、フォーム送信時にアクションを実行します。

action(文字列)Props

action が文字列の場合、<Form> コンポーネントは以下のPropsをサポートします:

Prop必須
actionaction="/search"string(URLまたは相対パス)はい
replacereplace={false}boolean-
scrollscroll={true}boolean-
prefetchprefetch={true}boolean-
  • action:フォーム送信時にナビゲーションするURL またはパス。
    • 空の文字列 "" は、更新されたsearchパラメータで同じルートにナビゲーションします。
  • replaceブラウザの履歴スタックに新しい履歴状態をプッシュする代わりに、現在の履歴状態を置き換えます。デフォルトは false です。
  • scroll:ナビゲーション時のスクロール動作を制御します。デフォルトは true で、新しいルートの先頭にスクロールし、前後のナビゲーションのスクロール位置を維持します。
  • prefetch:フォームがユーザーのビューポートに表示されたときに、パスをプリフェッチするかどうかを制御します。デフォルトは true です。

action(関数)Props

action が関数の場合、<Form> コンポーネントは以下のPropをサポートします:

Prop必須
actionaction={myAction}function(サーバーアクション)はい
  • action:フォーム送信時に呼び出されるサーバーアクション。詳細はReactドキュメントを参照してください。

補足action が関数の場合、replacescroll プロップは無視されます。

注意点

  • formAction<button> または <input type="submit"> フィールドで action プロップを上書きするために使用できます。Next.jsはクライアント側のナビゲーションを実行しますが、このアプローチはプリフェッチをサポートしません。
    • basePath を使用する場合、formAction パスにも含める必要があります。例:formAction="/base-path/search"
  • key:文字列 actionkey プロップを渡すことはサポートされていません。再レンダリングや変更を実行したい場合は、代わりに関数 action の使用を検討してください。
  • onSubmit:フォーム送信のロジックを処理するために使用できます。ただし、event.preventDefault()を呼び出すと、指定されたURLへのナビゲーションなど、<Form>の動作を上書きします。
  • methodencTypetarget<Form>の動作を上書きするため、サポートされていません。
    • 同様に、formMethodformEncTypeformTargetを使用して、それぞれmethodencTypetargetプロパティを上書きできますが、使用すると標準のブラウザ動作にフォールバックします。
    • これらのプロパティを使用する必要がある場合は、代わりにHTML <form>要素を使用してください。
  • <input type="file">actionが文字列の場合、ファイルオブジェクトの代わりにファイル名を送信することで、ブラウザの動作に一致します。

検索結果ページに遷移する検索フォーム

actionとしてパスを渡すことで、検索結果ページに遷移する検索フォームを作成できます:

/app/page.tsx
TypeScript
import Form from 'next/form'
 
export default function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <button type="submit">送信</button>
    </Form>
  )
}

ユーザーがクエリ入力フィールドを更新してフォームを送信すると、フォームデータは検索パラメータとしてURLにエンコードされます。例:/search?query=abc

補足actionに空文字列 "" を渡すと、フォームは更新された検索パラメータで同じルートにナビゲートします。

結果ページでは、searchParams page.jsプロパティを使用してクエリにアクセスし、外部ソースからデータを取得できます。

/app/search/page.tsx
TypeScript
import { getSearchResults } from '@/lib/search'
 
export default async function SearchPage({
  searchParams,
}: {
  searchParams: { [key: string]: string | string[] | undefined }
}) {
  const results = await getSearchResults(searchParams.query)
 
  return <div>...</div>
}

<Form>がユーザーのビューポートに表示されると、/searchページの共有UI(layout.jsloading.jsなど)がプリフェッチされます。送信時、フォームは新しいルートに即座にナビゲートし、結果が取得されている間、ロード中のUIを表示します。loading.jsを使用してフォールバックUIをデザインできます:

/app/search/loading.tsx
TypeScript
export default function Loading() {
  return <div>読み込み中...</div>
}

共有UIがまだ読み込まれていない場合に備えて、useFormStatusを使用してユーザーにすぐにフィードバックを表示できます。

まず、フォームが保留中の場合にロード状態を表示するコンポーネントを作成します:

/app/ui/search-button.tsx
TypeScript
'use client'
import { useFormStatus } from 'react-dom'
 
export default function SearchButton() {
  const status = useFormStatus()
  return (
    <button type="submit">{status.pending ? '検索中...' : '検索'}</button>
  )
}

次に、検索フォームページを更新してSearchButtonコンポーネントを使用します:

/app/page.tsx
TypeScript
import Form from 'next/form'
import { SearchButton } from '@/ui/search-button'
 
export default function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <SearchButton />
    </Form>
  )
}

サーバーアクションを使用した変更(ミューテーション)

actionプロパティに関数を渡すことで、変更を実行できます。

/app/posts/create/page.tsx
TypeScript
import Form from 'next/form'
import { createPost } from '@/posts/actions'
 
export default function Page() {
  return (
    <Form action={createPost}>
      <input name="title" />
      {/* ... */}
      <button type="submit">投稿を作成</button>
    </Form>
  )
}

変更後、通常は新しいリソースにリダイレクトします。next/navigationredirect関数を使用して、新しい投稿ページに移動できます。

補足:フォーム送信の「宛先」はアクションが実行されるまで不明なため、<Form>は共有UIを自動的にプリフェッチできません。

/app/posts/actions.ts
TypeScript
'use server'
import { redirect } from 'next/navigation'
 
export async function createPost(formData: FormData) {
  // 新しい投稿を作成
  // ...
 
  // 新しい投稿にリダイレクト
  redirect(`/posts/${data.id}`)
}

次に、新しいページでparamsプロパティを使用してデータを取得します:

/app/posts/[id]/page.tsx
TypeScript
import { getPost } from '@/posts/data'
 
export default async function PostPage({ params }: { params: { id: string } }) {
  const data = await getPost(params.id)
 
  return (
    <div>
      <h1>{data.title}</h1>
      {/* ... */}
    </div>
  )
}

より多くの例については、サーバーアクションのドキュメントを参照してください。