diff --git a/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts b/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts
index abab3c869..bcf8c4d5a 100644
--- a/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts
+++ b/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts
@@ -49,7 +49,7 @@ export default class HTMLDialogElement extends HTMLElement {
* @param value Return value.
*/
public set returnValue(value: string) {
- this[PropertySymbol.returnValue] = value;
+ this[PropertySymbol.returnValue] = String(value);
}
/**
@@ -79,10 +79,10 @@ export default class HTMLDialogElement extends HTMLElement {
*
* @param [returnValue] ReturnValue.
*/
- public close(returnValue = ''): void {
+ public close(returnValue?: string): void {
const wasOpen = this.open;
this.removeAttribute('open');
- this.returnValue = returnValue;
+ this.returnValue = returnValue !== undefined ? String(returnValue) : '';
if (wasOpen) {
this.dispatchEvent(new Event('close'));
}
diff --git a/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts b/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts
index de2cd5a27..5ea29f4e1 100644
--- a/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts
+++ b/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts
@@ -17,6 +17,7 @@ import ClassMethodBinder from '../../utilities/ClassMethodBinder.js';
import Node from '../node/Node.js';
import Element from '../element/Element.js';
import EventTarget from '../../event/EventTarget.js';
+import HTMLDialogElement from '../html-dialog-element/HTMLDialogElement.js';
import ElementEventAttributeUtility from '../element/ElementEventAttributeUtility.js';
/**
@@ -573,6 +574,26 @@ export default class HTMLFormElement extends HTMLElement {
* @param [submitter] Submitter.
*/
#submit(submitter?: HTMLInputElement | HTMLButtonElement): void {
+ const method = submitter?.formMethod || this.method;
+
+ if (method === 'dialog') {
+ let dialog: HTMLDialogElement | null = null;
+ let parent: Element = this;
+
+ while (parent) {
+ if (parent[PropertySymbol.tagName] === 'DIALOG') {
+ dialog = parent;
+ break;
+ }
+ parent = parent.parentElement;
+ }
+
+ if (dialog) {
+ dialog.close(submitter?.value);
+ return;
+ }
+ }
+
const action = submitter?.hasAttribute('formaction')
? submitter?.formAction || this.action
: this.action;
@@ -589,7 +610,6 @@ export default class HTMLFormElement extends HTMLElement {
return;
}
- const method = submitter?.formMethod || this.method;
const formData = new this[PropertySymbol.window].FormData(this);
let targetFrame: IBrowserFrame;
diff --git a/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts b/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts
index ca2304af7..f6a847dfe 100644
--- a/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts
+++ b/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts
@@ -3,6 +3,7 @@ import HTMLDialogElement from '../../../src/nodes/html-dialog-element/HTMLDialog
import Window from '../../../src/window/Window.js';
import Document from '../../../src/nodes/document/Document.js';
import { beforeEach, describe, it, expect } from 'vitest';
+import KeyboardEvent from '../../../src/event/events/KeyboardEvent.js';
describe('HTMLDialogElement', () => {
let window: Window;
@@ -83,6 +84,8 @@ describe('HTMLDialogElement', () => {
it('Should be possible to set manually', () => {
element.returnValue = 'foo';
expect(element.returnValue).toBe('foo');
+ element.returnValue = (undefined);
+ expect(element.returnValue).toBe('undefined');
});
});
@@ -105,6 +108,12 @@ describe('HTMLDialogElement', () => {
element.show();
element.close('foo');
expect(element.returnValue).toBe('foo');
+ element.show();
+ element.close(undefined);
+ expect(element.returnValue).toBe('');
+ element.show();
+ element.close((null));
+ expect(element.returnValue).toBe('null');
});
it('Should be possible to close the modal dialog with a return value', () => {
@@ -122,7 +131,7 @@ describe('HTMLDialogElement', () => {
expect(((dispatched)).bubbles).toBe(false);
});
- it('Should only dispatch a close event when dialog wasnt already closed', () => {
+ it("Should only dispatch a close event when dialog wasn't already closed", () => {
let dispatched: Event | null = null;
element.addEventListener('close', (event: Event) => (dispatched = event));
element.close();
diff --git a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
index 8b6f9986f..b684837af 100644
--- a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
+++ b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
@@ -930,6 +930,46 @@ describe('HTMLFormElement', () => {
expect(page.mainFrame.url).toBe('about:blank#blocked');
});
+
+ it('Supports form method "dialog"', () => {
+ const container = document.body;
+ container.innerHTML = ``;
+ const dialog = container.querySelector('dialog')!;
+ const form = dialog.querySelector('form')!;
+ const button = dialog.querySelector('button')!;
+ const input = dialog.querySelector('input')!;
+
+ input.value = 'test';
+
+ expect(dialog.returnValue).toBe('');
+ expect(dialog.open).toBe(false);
+
+ dialog.showModal();
+
+ expect(dialog.open).toBe(true);
+
+ let submitEvent: SubmitEvent | null = null;
+ dialog.addEventListener('submit', (event) => (submitEvent = event));
+ button.click();
+ expect(dialog.open).toBe(false);
+ expect(((submitEvent)).submitter).toBe(button);
+ expect(((submitEvent)).target).toBe(form);
+ expect(dialog.returnValue).toBe('buttonValue');
+
+ dialog.showModal();
+ expect(dialog.open).toBe(true);
+
+ form.submit();
+ expect(dialog.open).toBe(false);
+ expect(dialog.returnValue).toBe('');
+
+ expect(input.value).toBe('test');
+ });
});
describe('requestSubmit()', () => {