diff --git a/README.md b/README.md index a73ab18..bcd01c0 100755 --- a/README.md +++ b/README.md @@ -40,9 +40,29 @@ const swup = new Swup({ ## Server response +The server response must be a valid page with all containers to be replaced by swup. + +## Form attributes + Action, method and encoding type attributes set on the form are respected. -The server response must be a valid page with all containers to be replaced by swup. +[Externally associated inputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form) are +supported. Inputs and submit buttons that live outside the form but reference it via `form="form-id"` are +included in the submission. + +Submitter overrides are supported. If the submitter is a button, its `formaction`, `formmethod`, `formenctype` +and `formtarget` attributes override the form's corresponding attributes, matching native browser behavior. + +```html + +
+ + + + + + +``` ## Custom animations @@ -84,6 +104,10 @@ If you give a form an additional attribute `[data-swup-inline-form]`, swup will: } ``` +> **Note** Inline forms only replace the form's own container. Controls associated with an +> inline form via the `form` attribute but placed outside of it are **not** +> re-rendered on submit. + ## Options ### `formSelector` diff --git a/tests/unit/forms.test.ts b/tests/unit/forms.test.ts index 05a5f0f..2a129de 100644 --- a/tests/unit/forms.test.ts +++ b/tests/unit/forms.test.ts @@ -15,6 +15,8 @@ const createButton = (html: string) => { return new window.DOMParser().parseFromString(html, 'text/html').querySelector('button')!; }; +const parseDoc = (html: string) => new window.DOMParser().parseFromString(html, 'text/html'); + describe('appendQueryParams', () => { const empty = new FormData(); const data = new FormData(); @@ -225,3 +227,60 @@ describe('getFormInfo', () => { }); }); }); + +describe('getFormInfo with the form attribute', () => { + it('includes inputs associated via the form attribute in GET params', () => { + const doc = parseDoc( + '' + + '' + ); + const form = doc.querySelector('form')!; + expect(getFormInfo(form)).toMatchObject({ + href: 'http://localhost:3000/path?a=b#anchor', + url: '/path?a=b', + hash: '#anchor', + method: 'GET' + }); + }); + + it('includes inputs associated via the form attribute in POST body', () => { + const doc = parseDoc( + '' + + '' + ); + const form = doc.querySelector('form')!; + expect(getFormInfo(form)).toMatchObject({ + url: '/path', + method: 'POST', + body: new URLSearchParams({ a: 'b' }) + }); + }); + + it('includes the value of an externally associated submitter', () => { + const doc = parseDoc( + '' + + '' + ); + const form = doc.querySelector('form')!; + const submitter = doc.querySelector('button'); + expect(getFormInfo(form, submitter)).toMatchObject({ + url: '/path', + method: 'POST', + body: new URLSearchParams({ btn: 'go' }) + }); + }); + + it('reads formaction/formmethod from an externally associated submitter', () => { + const doc = parseDoc( + '' + + '' + ); + const form = doc.querySelector('form')!; + const submitter = doc.querySelector('button'); + expect(getFormInfo(form, submitter)).toMatchObject({ + action: 'http://localhost:3000/other', + url: '/other', + method: 'POST' + }); + }); +}); diff --git a/tests/unit/plugin.test.ts b/tests/unit/plugin.test.ts index 0706080..bfc71ea 100644 --- a/tests/unit/plugin.test.ts +++ b/tests/unit/plugin.test.ts @@ -11,6 +11,14 @@ const createForm = (html: string) => { return form; }; +const appendToBody =