diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx index 0e4741f4acd..a1e7f72bf01 100644 --- a/core/src/components/button/button.tsx +++ b/core/src/components/button/button.tsx @@ -195,9 +195,13 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf /** * If the form already has a rendered form button - * then do not append a new one again. + * then do not append a new one again. Sync the + * disabled state and type if it changes after button + * creation (e.g., runtime property updates). */ if (formButtonEl !== null && formEl.contains(formButtonEl)) { + formButtonEl.disabled = this.disabled; + formButtonEl.type = this.type; return; } diff --git a/packages/angular/test/base/e2e/src/lazy/form.spec.ts b/packages/angular/test/base/e2e/src/lazy/form.spec.ts index a5cacabe5e2..196a8cf26a4 100644 --- a/packages/angular/test/base/e2e/src/lazy/form.spec.ts +++ b/packages/angular/test/base/e2e/src/lazy/form.spec.ts @@ -282,7 +282,52 @@ test.describe('Form', () => { await expect(control).toHaveClass(/ng-invalid/); }); - }); + + test('should keep hidden submit button disabled state in sync', async ({ page }) => { + + // Get the disabled state of both visible and hidden button + const getDisabledState = () => + page.evaluate(() => { + const visible = document.querySelector( + '#submit-button' + ) as HTMLIonButtonElement; + + const hidden = document.querySelector( + 'form button[type="submit"][style*="display: none"]' + ) as HTMLButtonElement; + + return { + visible: visible?.disabled, + hidden: hidden?.disabled, + }; + }); + + // Ensure disabled state of both visible and hidden button + // Should match each other and expected + const expectDisabledStatesMatch = async (expected: boolean) => { + const state = await getDisabledState(); + expect(state.visible).toBe(expected); + expect(state.hidden).toBe(expected); + expect(state.visible).toBe(state.hidden); + return state; + }; + + // Initial state - should be disabled and both match + await expectDisabledStatesMatch(true); + + // Set form values - should be enabled + await page.locator('#set-values').click(); + + // After set values - should be enabled and both match + await expectDisabledStatesMatch(false); + + // User clicks submit button + await page.locator('#submit-button').click(); + + // Form should submit successfully + await expect(page.locator('#submit')).toHaveText('true'); + }); + }); // Helper functions async function testStatus(page: any, status: string) {