diff --git a/CHANGELOG.md b/CHANGELOG.md index ae829e6068c..5f39937f23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.5.7](https://github.com/ionic-team/ionic-framework/compare/v8.5.6...v8.5.7) (2025-05-07) + + +### Bug Fixes + +* **labels:** prevent clicking a label from triggering onClick twice on several components ([#30384](https://github.com/ionic-team/ionic-framework/issues/30384)) ([7d639b0](https://github.com/ionic-team/ionic-framework/commit/7d639b0412120523f758942c855cb69f9a52e9d9)), closes [#30165](https://github.com/ionic-team/ionic-framework/issues/30165) + + + + + ## [8.5.6](https://github.com/ionic-team/ionic-framework/compare/v8.5.5...v8.5.6) (2025-04-30) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index ed973dc865d..00a8312c7ea 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.5.7](https://github.com/ionic-team/ionic-framework/compare/v8.5.6...v8.5.7) (2025-05-07) + + +### Bug Fixes + +* **labels:** prevent clicking a label from triggering onClick twice on several components ([#30384](https://github.com/ionic-team/ionic-framework/issues/30384)) ([7d639b0](https://github.com/ionic-team/ionic-framework/commit/7d639b0412120523f758942c855cb69f9a52e9d9)), closes [#30165](https://github.com/ionic-team/ionic-framework/issues/30165) + + + + + ## [8.5.6](https://github.com/ionic-team/ionic-framework/compare/v8.5.5...v8.5.6) (2025-04-30) diff --git a/core/package-lock.json b/core/package-lock.json index 7fdce873b84..214b52756e7 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/core", - "version": "8.5.6", + "version": "8.5.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/core", - "version": "8.5.6", + "version": "8.5.7", "license": "MIT", "dependencies": { "@stencil/core": "4.20.0", diff --git a/core/package.json b/core/package.json index 2e97bba2d9d..4b04912cbd9 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/core", - "version": "8.5.6", + "version": "8.5.7", "description": "Base components for Ionic", "keywords": [ "ionic", diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx index 3b9c3e6724a..4a9132665fd 100644 --- a/core/src/components/checkbox/checkbox.tsx +++ b/core/src/components/checkbox/checkbox.tsx @@ -199,6 +199,14 @@ export class Checkbox implements ComponentInterface { this.toggleChecked(ev); }; + /** + * Stops propagation when the display label is clicked, + * otherwise, two clicks will be triggered. + */ + private onDivLabelClick = (ev: MouseEvent) => { + ev.stopPropagation(); + }; + private getHintTextID(): string | undefined { const { el, helperText, errorText, helperTextId, errorTextId } = this; @@ -314,6 +322,7 @@ export class Checkbox implements ComponentInterface { }} part="label" id={this.inputLabelId} + onClick={this.onDivLabelClick} > {this.renderHintText()} diff --git a/core/src/components/checkbox/test/basic/checkbox.e2e.ts b/core/src/components/checkbox/test/basic/checkbox.e2e.ts index 1a41b339599..159e86f9a30 100644 --- a/core/src/components/checkbox/test/basic/checkbox.e2e.ts +++ b/core/src/components/checkbox/test/basic/checkbox.e2e.ts @@ -99,4 +99,38 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => expect(ionChange).not.toHaveReceivedEvent(); }); }); + + test.describe(title('checkbox: click'), () => { + test('should trigger onclick only once when clicking the label', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/30165', + }); + + // Create a spy function in page context + await page.setContent(`Test Checkbox`, config); + + // Track calls to the exposed function + let clickCount = 0; + page.on('console', (msg) => { + if (msg.text().includes('click called')) { + clickCount++; + } + }); + + const input = page.locator('div.label-text-wrapper'); + + // Use position to make sure we click into the label enough to trigger + // what would be the double click + await input.click({ + position: { + x: 5, + y: 5, + }, + }); + + // Verify the click was triggered exactly once + expect(clickCount).toBe(1); + }); + }); }); diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index 5f4b1257141..c2834138aa8 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -720,6 +720,18 @@ export class Input implements ComponentInterface { return this.label !== undefined || this.labelSlot !== null; } + /** + * Stops propagation when the label is clicked, + * otherwise, two clicks will be triggered. + */ + private onLabelClick = (ev: MouseEvent) => { + // Only stop propagation if the click was directly on the label + // and not on the input or other child elements + if (ev.target === ev.currentTarget) { + ev.stopPropagation(); + } + }; + /** * Renders the border container * when fill="outline". @@ -815,9 +827,9 @@ export class Input implements ComponentInterface { * interactable, clicking the label would focus that instead * since it comes before the input in the DOM. */} -