diff --git a/.changeset/plenty-turtles-remember.md b/.changeset/plenty-turtles-remember.md new file mode 100644 index 000000000..e6b58502b --- /dev/null +++ b/.changeset/plenty-turtles-remember.md @@ -0,0 +1,7 @@ +--- +'@lion/ui': minor +--- + +BREAKING CHANGE: + +[form] set focus to the first erroneous form element on submit diff --git a/docs/components/form/overview.md b/docs/components/form/overview.md index 02225f2ae..6d08d6860 100644 --- a/docs/components/form/overview.md +++ b/docs/components/form/overview.md @@ -11,14 +11,25 @@ A web component that enhances the functionality of the native `form` component. It is designed to interact with (instances of) the [form controls](../../fundamentals/systems/form/overview.md). ```js preview-story -export const main = () => html` - -
- - -
-
-`; +export const main = () => { + const submitHandler = ev => { + const formData = ev.target.serializedValue; + console.log('formData', formData); + fetch('/api/foo/', { + method: 'POST', + body: JSON.stringify(formData), + }); + }; + return html` + +
ev.preventDefault()}> + + + +
+
+ `; +}; ``` ## Features diff --git a/docs/components/form/use-cases.md b/docs/components/form/use-cases.md index 5fd0f74ee..d8f7f895f 100644 --- a/docs/components/form/use-cases.md +++ b/docs/components/form/use-cases.md @@ -10,32 +10,28 @@ import '@lion/ui/define/lion-form.js'; ## Submit & Reset -To submit a form, use a regular button (or `LionButtonSubmit`) somewhere inside the native `
`. +To submit a form, use a regular ` +
`); @@ -202,4 +202,68 @@ describe('', () => { expect(dispatchSpy.args[0][0].type).to.equal('reset'); expect(internalHandlerSpy).to.be.calledBefore(dispatchSpy); }); + + it('sets focus on submit to the first erroneous form element', async () => { + const el = await fixture(html` + +
+ <${childTag} name="firstName" .modelValue=${'Foo'} .validators=${[ + new Required(), + ]}> + <${childTag} name="lastName" .validators=${[new Required()]}> + +
+
+ `); + const button = /** @type {HTMLButtonElement} */ (el.querySelector('button')); + const dispatchSpy = spy(el, 'dispatchEvent'); + button.click(); + expect(dispatchSpy.args[0][0].type).to.equal('submit'); + // @ts-ignore [allow-protected] in test + expect(document.activeElement).to.equal(el.formElements[1]._inputNode); + }); + + it('sets focus on submit to the first erroneous form element with a fieldset', async () => { + const el = await fixture(html` + +
+ + <${childTag} name="firstName" .modelValue=${'Foo'} .validators=${[ + new Required(), + ]}> + <${childTag} name="lastName" .validators=${[new Required()]}> + + +
+
+ `); + const button = /** @type {HTMLButtonElement} */ (el.querySelector('button')); + const dispatchSpy = spy(el, 'dispatchEvent'); + button.click(); + expect(dispatchSpy.args[0][0].type).to.equal('submit'); + const fieldset = el.formElements[0]; + // @ts-ignore [allow-protected] in test + expect(document.activeElement).to.equal(fieldset.formElements[1]._inputNode); + }); + + it('sets focus on submit to the first form element within a erroneous fieldset', async () => { + const el = await fixture(html` + +
+ + <${childTag} name="firstName"> + <${childTag} name="lastName"> + + +
+
+ `); + const button = /** @type {HTMLButtonElement} */ (el.querySelector('button')); + const dispatchSpy = spy(el, 'dispatchEvent'); + button.click(); + expect(dispatchSpy.args[0][0].type).to.equal('submit'); + const fieldset = el.formElements[0]; + // @ts-ignore [allow-protected] in test + expect(document.activeElement).to.equal(fieldset.formElements[0]._inputNode); + }); });