Skip to content

Commit

Permalink
fix(ui): fix focus first erroneous for listbox
Browse files Browse the repository at this point in the history
  • Loading branch information
tlouisse committed Jul 23, 2024
1 parent 856c265 commit 1dce98d
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/tender-moles-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@lion/ui": patch
---

fix focus first erroneous for listbox
13 changes: 11 additions & 2 deletions packages/ui/components/form/src/LionForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ const throwFormNodeError = () => {
);
};

/**
* @param {FormRegistrarHost} formEl
* @returns {boolean}
*/
function hasFocusableChildren(formEl) {
// this implies all children have the same type (either all of them are focusable or none of them are)
return formEl.formElements?.some(child => child._focusableNode);
}

/**
* LionForm: form wrapper providing extra features and integration with lion-field elements.
*
Expand Down Expand Up @@ -63,7 +72,7 @@ export class LionForm extends LionFieldset {
this.dispatchEvent(new Event('submit', { bubbles: true }));

if (this.hasFeedbackFor?.includes('error')) {
this._setFocusOnFirstErroneousFormElement(this);
this._setFocusOnFirstErroneousFormElement(/** @type { * & FormRegistrarHost } */ (this));
}
}

Expand Down Expand Up @@ -95,7 +104,7 @@ export class LionForm extends LionFieldset {
element.formElements.find(child => child.hasFeedbackFor.includes('error')) ||
element.formElements[0];

if (firstFormElWithError.formElements?.length > 0) {
if (hasFocusableChildren(firstFormElWithError)) {
this._setFocusOnFirstErroneousFormElement(firstFormElWithError);
} else {
firstFormElWithError._focusableNode.focus();
Expand Down
23 changes: 21 additions & 2 deletions packages/ui/components/form/test/lion-form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import '@lion/ui/define/lion-fieldset.js';
import { LionField, Required } from '@lion/ui/form-core.js';
import '@lion/ui/define/lion-field.js';
import '@lion/ui/define/lion-validation-feedback.js';

import '@lion/ui/define/lion-listbox.js';
import '@lion/ui/define/lion-option.js';
import '@lion/ui/define/lion-form.js';
import {
aTimeout,
Expand Down Expand Up @@ -223,7 +224,7 @@ describe('<lion-form>', () => {
expect(document.activeElement).to.equal(el.formElements[1]._inputNode);
});

it('sets focus on submit to the first erroneous form element with a fieldset', async () => {
it('sets focus on submit to the first erroneous form element within a fieldset', async () => {
const el = await fixture(html`
<lion-form>
<form>
Expand Down Expand Up @@ -266,4 +267,22 @@ describe('<lion-form>', () => {
// @ts-ignore [allow-protected] in test
expect(document.activeElement).to.equal(fieldset.formElements[0]._inputNode);
});

it('sets focus on submit to the first form element within a erroneous listbox', async () => {
const el = await fixture(html`
<lion-form>
<form>
<lion-listbox name="name" .validators="${[new Required()]}">
<lion-option value="a">a</lion-option>
<lion-option value="b">b</lion-option>
</lion-listbox>
<button type="submit">submit</button>
</form>
</lion-form>
`);
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
button.click();
const listboxEl = el.formElements[0];
expect(document.activeElement).to.equal(listboxEl._inputNode);
});
});

0 comments on commit 1dce98d

Please sign in to comment.