diff --git a/examples/next-forms/.eslintrc.json b/examples/next-forms/.eslintrc.json
new file mode 100644
index 0000000000000..bffb357a71225
--- /dev/null
+++ b/examples/next-forms/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/examples/next-forms/.gitignore b/examples/next-forms/.gitignore
new file mode 100644
index 0000000000000..1437c53f70bc2
--- /dev/null
+++ b/examples/next-forms/.gitignore
@@ -0,0 +1,34 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# vercel
+.vercel
diff --git a/examples/next-forms/README.md b/examples/next-forms/README.md
new file mode 100644
index 0000000000000..2d04b96993d80
--- /dev/null
+++ b/examples/next-forms/README.md
@@ -0,0 +1,27 @@
+# Building Web Forms with Next.js Example
+
+This example shows how you can build forms with Next.js.
+
+## Preview
+
+Preview the example live on [StackBlitz](http://stackblitz.com/):
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/next-forms)
+
+## Deploy your own
+
+Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/next-forms&project-name=next-forms&repository-name=next-forms)
+
+## How to use
+
+Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
+
+```bash
+npx create-next-app --example next-forms next-forms-app
+# or
+yarn create next-app --example next-forms next-forms-app
+```
+
+Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
diff --git a/examples/next-forms/next.config.js b/examples/next-forms/next.config.js
new file mode 100644
index 0000000000000..0d6071006ab35
--- /dev/null
+++ b/examples/next-forms/next.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ reactStrictMode: true,
+}
diff --git a/examples/next-forms/package.json b/examples/next-forms/package.json
new file mode 100644
index 0000000000000..9c52e1770b0ff
--- /dev/null
+++ b/examples/next-forms/package.json
@@ -0,0 +1,18 @@
+{
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "next": "latest",
+ "react": "17.0.2",
+ "react-dom": "17.0.2"
+ },
+ "devDependencies": {
+ "eslint": "8.4.1",
+ "eslint-config-next": "latest"
+ }
+}
diff --git a/examples/next-forms/pages/_app.js b/examples/next-forms/pages/_app.js
new file mode 100644
index 0000000000000..1e1cec92425c8
--- /dev/null
+++ b/examples/next-forms/pages/_app.js
@@ -0,0 +1,7 @@
+import '../styles/globals.css'
+
+function MyApp({ Component, pageProps }) {
+ return
+}
+
+export default MyApp
diff --git a/examples/next-forms/pages/api/form.js b/examples/next-forms/pages/api/form.js
new file mode 100644
index 0000000000000..d3afc36812996
--- /dev/null
+++ b/examples/next-forms/pages/api/form.js
@@ -0,0 +1,12 @@
+export default function handler(req, res) {
+ const body = req.body
+ console.log('body: ', body)
+
+ // Both of these are required.
+ if (!body.first || !body.last) {
+ return res.json({ data: 'First or last name not found' })
+ }
+
+ // Found the name.
+ res.json({ data: `${body.first} ${body.last}` })
+}
diff --git a/examples/next-forms/pages/index.js b/examples/next-forms/pages/index.js
new file mode 100644
index 0000000000000..485abd8cd3647
--- /dev/null
+++ b/examples/next-forms/pages/index.js
@@ -0,0 +1,53 @@
+import Head from 'next/head'
+import Image from 'next/image'
+import Link from 'next/link'
+import styles from '../styles/Home.module.css'
+
+export default function Home() {
+ return (
+
+
+
Next.js forms
+
+
+
+
+
+
+
+
+ Get started by looking at{' '}
+ pages/js-form.js
and{' '}
+ pages/no-js-form.js
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/next-forms/pages/js-form.js b/examples/next-forms/pages/js-form.js
new file mode 100644
index 0000000000000..3dd90a9a59a08
--- /dev/null
+++ b/examples/next-forms/pages/js-form.js
@@ -0,0 +1,61 @@
+import Link from 'next/link'
+import styles from '../styles/Home.module.css'
+
+export default function PageWithJSbasedForm() {
+ // Handle the submit event on form submit.
+ const handleSubmit = async (event) => {
+ // Stop the form from submitting and refreshing the page.
+ event.preventDefault()
+
+ // Get data from the form.
+ const data = {
+ first: event.target.first.value,
+ last: event.target.last.value,
+ }
+
+ const JSONdata = JSON.stringify(data)
+
+ // Send the form data to our API and get a response.
+ const response = await fetch('/api/form', {
+ // Body of the request is the JSON data we created above.
+ body: JSONdata,
+
+ // Tell the server we're sending JSON.
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ // The method is POST because we are sending data.
+ method: 'POST',
+ })
+
+ // Get the response data from server as JSON.
+ // If server returns the name submitted, that means the form works.
+ const result = await response.json()
+ alert(`Is this your full name: ${result.data}`)
+ }
+ return (
+
+
+ Form{' '}
+
+ with
+ {' '}
+ JavaScript.
+
+
+
+ Get started by looking at{' '}
+ pages/js-from.js
+
+
+
+
+ )
+}
diff --git a/examples/next-forms/pages/no-js-form.js b/examples/next-forms/pages/no-js-form.js
new file mode 100644
index 0000000000000..8a5a8f6fb62d4
--- /dev/null
+++ b/examples/next-forms/pages/no-js-form.js
@@ -0,0 +1,33 @@
+import Link from 'next/link'
+import styles from '../styles/Home.module.css'
+
+export default function Form() {
+ return (
+
+
+ Form{' '}
+
+ without
+ {' '}
+ JavaScript.
+
+
+ Get started by looking at{' '}
+ pages/no-js-from.js
+
+
+ {/*action: The action attribute defines where the data gets sent. Its value must be a valid relative or absolute URL. If this attribute isn't provided, the data will be sent to the URL of the page containing the form — the current page.
+ method: The HTTP method to submit the form with. (case insensitive) s*/}
+
+
+
+ )
+}
diff --git a/examples/next-forms/public/favicon.ico b/examples/next-forms/public/favicon.ico
new file mode 100644
index 0000000000000..718d6fea4835e
Binary files /dev/null and b/examples/next-forms/public/favicon.ico differ
diff --git a/examples/next-forms/public/vercel.svg b/examples/next-forms/public/vercel.svg
new file mode 100644
index 0000000000000..fbf0e25a651c2
--- /dev/null
+++ b/examples/next-forms/public/vercel.svg
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/examples/next-forms/styles/Home.module.css b/examples/next-forms/styles/Home.module.css
new file mode 100644
index 0000000000000..35454bb748190
--- /dev/null
+++ b/examples/next-forms/styles/Home.module.css
@@ -0,0 +1,121 @@
+.container {
+ min-height: 100vh;
+ padding: 0 0.5rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+}
+
+.main {
+ padding: 5rem 0;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.footer {
+ width: 100%;
+ height: 100px;
+ border-top: 1px solid #eaeaea;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.footer a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-grow: 1;
+}
+
+.title a {
+ color: #0070f3;
+ text-decoration: none;
+}
+
+.title a:hover,
+.title a:focus,
+.title a:active {
+ text-decoration: underline;
+}
+
+.title {
+ margin: 0;
+ line-height: 1.15;
+ font-size: 4rem;
+}
+
+.title,
+.description {
+ text-align: center;
+}
+
+.description {
+ line-height: 1.5;
+ font-size: 1.5rem;
+}
+
+.code {
+ background: #fafafa;
+ border-radius: 5px;
+ padding: 0.75rem;
+ font-size: 1.1rem;
+ font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
+ Bitstream Vera Sans Mono, Courier New, monospace;
+}
+
+.grid {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ max-width: 800px;
+ margin-top: 3rem;
+}
+
+.card {
+ margin: 1rem;
+ padding: 1.5rem;
+ text-align: left;
+ color: inherit;
+ text-decoration: none;
+ border: 1px solid #eaeaea;
+ border-radius: 10px;
+ transition: color 0.15s ease, border-color 0.15s ease;
+ width: 45%;
+}
+
+.card:hover,
+.card:focus,
+.card:active {
+ color: #0070f3;
+ border-color: #0070f3;
+}
+
+.card h2 {
+ margin: 0 0 1rem 0;
+ font-size: 1.5rem;
+}
+
+.card p {
+ margin: 0;
+ font-size: 1.25rem;
+ line-height: 1.5;
+}
+
+.logo {
+ height: 1em;
+ margin-left: 0.5rem;
+}
+
+@media (max-width: 600px) {
+ .grid {
+ width: 100%;
+ flex-direction: column;
+ }
+}
diff --git a/examples/next-forms/styles/globals.css b/examples/next-forms/styles/globals.css
new file mode 100644
index 0000000000000..1114e3bad5dc9
--- /dev/null
+++ b/examples/next-forms/styles/globals.css
@@ -0,0 +1,72 @@
+html,
+body {
+ padding: 0;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
+ Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+form {
+ display: table;
+ min-width: 350px;
+ margin: 0 auto;
+ padding: 1rem;
+}
+
+label {
+ display: table;
+ width: 100%;
+ margin-bottom: 0.5rem;
+ color: #3b3b3b;
+}
+
+input {
+ display: table;
+ width: 100%;
+ padding: 0.5rem;
+ border: 1px solid #ccc;
+ border-radius: 0.25rem;
+ box-sizing: border-box;
+ margin-bottom: 2.5rem;
+}
+
+input:focus {
+ outline: none;
+ border-color: #0070f3;
+}
+
+button {
+ display: table;
+ width: 100%;
+ padding: 0.5rem;
+ border: none;
+ border-radius: 0.25rem;
+ box-sizing: border-box;
+ margin-bottom: 2.5rem;
+ background-color: #0070f3;
+ color: #fff;
+ cursor: pointer;
+}
+
+button:hover {
+ background-color: #0060e9;
+}
+
+.container {
+ min-height: 100vh;
+ padding: 0 0.5rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+}