Skip to content

Commit

Permalink
feat(button): forms will submit with Enter key (#1120)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arturo Castillo Delgado authored Jul 13, 2022
1 parent 9a9024f commit 73af76f
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
16 changes: 16 additions & 0 deletions packages/components/src/components/button/button.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,20 @@ describe('scale-button', () => {
const element = await page.find('scale-icon-action-search');
expect(element.getAttribute('size')).toBe('16');
});

it('should allow submitting forms with the Enter key', async () => {
const page = await newE2EPage();
await page.setContent(`
<form>
<input type="text" name="a" />
<input type="text" name="b" />
<scale-button>Submit</scale-button>
</form>
`);
const form = await page.find('form');
const input = await page.find('input[name="a"]');
const spy = await form.spyOnEvent('submit');
await input.press('Enter');
expect(spy).toHaveReceivedEvent();
});
});
48 changes: 45 additions & 3 deletions packages/components/src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class Button {
@Prop() innerTabindex?: number;

private focusableElement: HTMLElement;
private fallbackSubmitInputElement: HTMLInputElement;

/**
* Prevent clicks from being emitted from the host
Expand All @@ -88,16 +89,16 @@ export class Button {
handleClick = (ev: Event) => {
// No need to check for `disabled` because disabled buttons won't emit clicks
if (hasShadowDom(this.hostElement)) {
const form = this.hostElement.closest('form');
if (form) {
const parentForm = this.hostElement.closest('form');
if (parentForm) {
ev.preventDefault();

const fakeButton = document.createElement('button');
if (this.type) {
fakeButton.type = this.type;
}
fakeButton.style.display = 'none';
form.appendChild(fakeButton);
parentForm.appendChild(fakeButton);
fakeButton.click();
fakeButton.remove();
}
Expand All @@ -106,12 +107,53 @@ export class Button {

connectedCallback() {
this.setIconPositionProp();
this.appendEnterKeySubmitFallback();
}

componentDidLoad() {
this.setChildrenIconSize();
}

disconnectedCallback() {
this.cleanUpEnterKeySubmitFallback();
}

/**
* In order for forms to be submitted with the Enter key
* there has to be a `button` or an `input[type="submit"]` in the form.
* Browsers do not take the <button> inside the Shadow DOM into account for this matter.
* So we carefully append an `input[type="submit"]` to overcome this.
*
* @see https://stackoverflow.com/a/35235768
* @see https://github.com/telekom/scale/issues/859
*/
appendEnterKeySubmitFallback() {
if (hasShadowDom(this.hostElement)) {
const parentForm = this.hostElement.closest('form');
if (parentForm == null) {
return;
}
const hasSubmitInputAlready =
parentForm.querySelector('input[type="submit"]') != null;
if (hasSubmitInputAlready) {
return;
}
this.fallbackSubmitInputElement = document.createElement('input');
this.fallbackSubmitInputElement.type = 'submit';
this.fallbackSubmitInputElement.hidden = true;
parentForm.appendChild(this.fallbackSubmitInputElement);
}
}

cleanUpEnterKeySubmitFallback() {
if (this.fallbackSubmitInputElement != null) {
try {
this.fallbackSubmitInputElement.remove();
this.fallbackSubmitInputElement = null;
} catch (err) {}
}
}

/**
* Detect whether the last node is an element (not text).
* If so, it's probably an icon, so we set `iconPosition` to `after`.
Expand Down

0 comments on commit 73af76f

Please sign in to comment.