Forms
Submit forms without leaving the page, with the same transitions as links.
Import it from pagefold/forms (about 1.5 KB minified and compressed, shared code included).
import PagefoldForms from 'pagefold/forms'
new Pagefold({ plugins: [new PagefoldForms()] })
<form data-pagefold-form action="/search" method="get">
<input name="q" />
<button>Search</button>
</form>
Which forms it handles
A submit goes through these questions in order. The first “yes” leaves the form to the browser:
- Did something already cancel the submit? Another listener called preventDefault().Yes → browser
- Does the form not match formSelector? By default only forms with data-pagefold-form.Yes → browser
- Is the method neither GET nor POST? For example method="dialog".Yes → browser
- Does it have target="_blank"?Yes → browser
- Is it to another origin, or does ignoreVisit return true?Yes → browser
- Pagefold submits it as a visit, with the transition.
Yes: The browser submits the form normally.
GET and POST
- GET forms become a visit to the action URL with the fields as query string:
/search?q=cats. The result is cached like any page. - POST forms send the fields in the request body, as
application/x-www-form-urlencodedor, withenctype="multipart/form-data", asFormData. The cache is never used. The server’s response is shown like any other page.
A submit button can override the form with formaction, formmethod, formenctype and formtarget, and its own name and value are sent.
What is left to the browser
Forms to another origin, with target="_blank" (which fires form:submit:newtab), with method="dialog", that already had their submit cancelled, or that match ignoreVisit.
Inline forms
A form marked data-pagefold-inline-form replaces only itself, not the containers of the page. The rest of the page stays as it is, and the animation classes go on the form instead of on html. After the answer arrives the page scrolls back to the start of the form.
<form id="newsletter" class="transition-form" data-pagefold-inline-form action="/subscribe" method="post">
<input name="email">
<button>Subscribe</button>
</form>
.transition-form.is-changing { transition: opacity 0.2s; }
.transition-form.is-animating { opacity: 0; }
The form needs an id: it is how the form in the answer is found. Without one Pagefold warns in the console and treats the form like any other. The server must answer with a page that contains a form with the same id.
Empty fields
A GET form sends every field, including the empty ones: ?q=cats&tag=. With stripEmptyParams: true the empty ones are left out and the address is ?q=cats.
Hook
form:submit fires before the visit with { el, event }. Replace its default behavior and you take over the submission, including calling event.preventDefault(): if you do not, the browser submits the form.
pagefold.hooks.on('form:submit', (visit, { el }) => {
analytics.track('submit', { form: el.id })
})
form:submit:newtab fires instead when the form opens a new tab (target="_blank"). The form is left to the browser, and you can still react to it.
Common problems
- The form reloads the page. By default only forms with
data-pagefold-formare handled. Add it, or setformSelector: 'form'. - A POST result looks out of date. It is never read from or written to the cache, so it is the server’s current answer.
- My own submit handler stopped working. If another listener called
preventDefault()first, the plugin leaves the form alone.
Options
| Option | Type | Default | What it does |
|---|---|---|---|
formSelector | string | 'form[data-pagefold-form]' | Which forms are handled. By default, only forms with data-pagefold-form. Use "form" for all. |
inlineFormSelector | string | 'form[data-pagefold-inline-form]' | Forms that replace only themselves instead of the containers of the page. |
stripEmptyParams | boolean | false | Leave empty fields out of the address of a GET form. |