diff --git a/.github/actions/publish-npm/action.yml b/.github/actions/publish-npm/action.yml index d3e06d5fb01..6913b493ef1 100644 --- a/.github/actions/publish-npm/action.yml +++ b/.github/actions/publish-npm/action.yml @@ -22,7 +22,7 @@ runs: using: 'composite' steps: - name: 🟒 Configure Node for Publish - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ inputs.node-version }} registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/actions/build-angular-server/action.yml b/.github/workflows/actions/build-angular-server/action.yml index b5d37c5a9ac..e21a39669bf 100644 --- a/.github/workflows/actions/build-angular-server/action.yml +++ b/.github/workflows/actions/build-angular-server/action.yml @@ -3,7 +3,7 @@ description: 'Build Ionic Angular Server' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-angular/action.yml b/.github/workflows/actions/build-angular/action.yml index 5224f9741e0..12e1db1f5dc 100644 --- a/.github/workflows/actions/build-angular/action.yml +++ b/.github/workflows/actions/build-angular/action.yml @@ -3,7 +3,7 @@ description: 'Build Ionic Angular' runs: using: 'composite' steps: - - uses: actions/setup-node@v6 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-core-stencil-prerelease/action.yml b/.github/workflows/actions/build-core-stencil-prerelease/action.yml index ea488bb3723..da6019ce5b3 100644 --- a/.github/workflows/actions/build-core-stencil-prerelease/action.yml +++ b/.github/workflows/actions/build-core-stencil-prerelease/action.yml @@ -9,7 +9,7 @@ runs: using: 'composite' steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x diff --git a/.github/workflows/actions/build-core/action.yml b/.github/workflows/actions/build-core/action.yml index 81d5f838246..15ec2d916f4 100644 --- a/.github/workflows/actions/build-core/action.yml +++ b/.github/workflows/actions/build-core/action.yml @@ -9,7 +9,7 @@ runs: using: 'composite' steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/build-react-router/action.yml b/.github/workflows/actions/build-react-router/action.yml index c8083494b0a..b104ebd429d 100644 --- a/.github/workflows/actions/build-react-router/action.yml +++ b/.github/workflows/actions/build-react-router/action.yml @@ -3,7 +3,7 @@ description: 'Build Ionic React Router' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-react/action.yml b/.github/workflows/actions/build-react/action.yml index 5899335ad3e..5335ea47af2 100644 --- a/.github/workflows/actions/build-react/action.yml +++ b/.github/workflows/actions/build-react/action.yml @@ -3,7 +3,7 @@ description: 'Build Ionic React' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-vue-router/action.yml b/.github/workflows/actions/build-vue-router/action.yml index 9b07ce64973..bf47bb0dec3 100644 --- a/.github/workflows/actions/build-vue-router/action.yml +++ b/.github/workflows/actions/build-vue-router/action.yml @@ -3,7 +3,7 @@ description: 'Builds Ionic Vue Router' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-vue/action.yml b/.github/workflows/actions/build-vue/action.yml index 5c7497ec359..4a7375786d2 100644 --- a/.github/workflows/actions/build-vue/action.yml +++ b/.github/workflows/actions/build-vue/action.yml @@ -3,7 +3,7 @@ description: 'Build Ionic Vue' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/download-archive/action.yml b/.github/workflows/actions/download-archive/action.yml index 2acddf9713f..97f07f8627a 100644 --- a/.github/workflows/actions/download-archive/action.yml +++ b/.github/workflows/actions/download-archive/action.yml @@ -10,7 +10,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ inputs.name }} path: ${{ inputs.path }} diff --git a/.github/workflows/actions/test-angular-e2e/action.yml b/.github/workflows/actions/test-angular-e2e/action.yml index f12fee784e8..8a15bfb5037 100644 --- a/.github/workflows/actions/test-angular-e2e/action.yml +++ b/.github/workflows/actions/test-angular-e2e/action.yml @@ -6,7 +6,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-core-clean-build/action.yml b/.github/workflows/actions/test-core-clean-build/action.yml index 96abc90121c..25c9a202652 100644 --- a/.github/workflows/actions/test-core-clean-build/action.yml +++ b/.github/workflows/actions/test-core-clean-build/action.yml @@ -3,7 +3,7 @@ description: 'Test Core Clean Build' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x diff --git a/.github/workflows/actions/test-core-lint/action.yml b/.github/workflows/actions/test-core-lint/action.yml index f9f0011719a..66a3036ef04 100644 --- a/.github/workflows/actions/test-core-lint/action.yml +++ b/.github/workflows/actions/test-core-lint/action.yml @@ -3,7 +3,7 @@ description: 'Test Core Lint' runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/test-core-screenshot/action.yml b/.github/workflows/actions/test-core-screenshot/action.yml index 1f8699e66d4..379ce934edc 100644 --- a/.github/workflows/actions/test-core-screenshot/action.yml +++ b/.github/workflows/actions/test-core-screenshot/action.yml @@ -13,7 +13,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive @@ -66,7 +66,7 @@ runs: working-directory: ./core - name: πŸ“¦ Archive Updated Screenshots if: inputs.update == 'true' && steps.test-and-update.outputs.hasUpdatedScreenshots == 'true' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: updated-screenshots-${{ inputs.shard }}-${{ inputs.totalShards }} path: UpdatedScreenshots-${{ inputs.shard }}-${{ inputs.totalShards }}.zip diff --git a/.github/workflows/actions/test-core-spec/action.yml b/.github/workflows/actions/test-core-spec/action.yml index 2aab4b1be94..f33ab0aa3e3 100644 --- a/.github/workflows/actions/test-core-spec/action.yml +++ b/.github/workflows/actions/test-core-spec/action.yml @@ -6,7 +6,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/test-react-e2e/action.yml b/.github/workflows/actions/test-react-e2e/action.yml index a1bcbf7a4db..af6100bdb07 100644 --- a/.github/workflows/actions/test-react-e2e/action.yml +++ b/.github/workflows/actions/test-react-e2e/action.yml @@ -6,7 +6,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-react-router-e2e/action.yml b/.github/workflows/actions/test-react-router-e2e/action.yml index 034cfdce747..663ae0be575 100644 --- a/.github/workflows/actions/test-react-router-e2e/action.yml +++ b/.github/workflows/actions/test-react-router-e2e/action.yml @@ -6,7 +6,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-vue-e2e/action.yml b/.github/workflows/actions/test-vue-e2e/action.yml index 191cd193c8a..5f7de702d08 100644 --- a/.github/workflows/actions/test-vue-e2e/action.yml +++ b/.github/workflows/actions/test-vue-e2e/action.yml @@ -6,7 +6,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/update-reference-screenshots/action.yml b/.github/workflows/actions/update-reference-screenshots/action.yml index 6ee56689b10..844f4e6d2ac 100644 --- a/.github/workflows/actions/update-reference-screenshots/action.yml +++ b/.github/workflows/actions/update-reference-screenshots/action.yml @@ -7,10 +7,10 @@ on: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: ./artifacts - name: πŸ”Ž Extract Archives diff --git a/.github/workflows/actions/upload-archive/action.yml b/.github/workflows/actions/upload-archive/action.yml index c09397345f9..3cfff8853fc 100644 --- a/.github/workflows/actions/upload-archive/action.yml +++ b/.github/workflows/actions/upload-archive/action.yml @@ -13,7 +13,7 @@ runs: - name: πŸ—„οΈ Create Archive run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }} shell: bash - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ inputs.name }} path: ${{ inputs.output }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ccdc9b996d2..74f504e7317 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -15,7 +15,7 @@ jobs: security-events: write steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: github/codeql-action/init@v4 + - uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: languages: javascript - - uses: github/codeql-action/analyze@v4 + - uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 diff --git a/.github/workflows/conventional-commit.yml b/.github/workflows/conventional-commit.yml index 8c0bbdebb37..65c026de5eb 100644 --- a/.github/workflows/conventional-commit.yml +++ b/.github/workflows/conventional-commit.yml @@ -12,7 +12,7 @@ jobs: if: | !contains(github.event.pull_request.title, 'release') && !contains(github.event.pull_request.title, 'chore') - uses: amannn/action-semantic-pull-request@v6 + uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 7f5d8de9787..b6014addef1 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -13,7 +13,7 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" sync-labels: true diff --git a/CHANGELOG.md b/CHANGELOG.md index e16c678580a..996f23da565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **angular-server:** fallback to scoped+annotations when SSR DOM lacks attachShadow ([#30967](https://github.com/ionic-team/ionic-framework/issues/30967)) ([ae6911f](https://github.com/ionic-team/ionic-framework/commit/ae6911f6c8d46467ae54114295688bbba5ccbf5e)), closes [#29751](https://github.com/ionic-team/ionic-framework/issues/29751) +* **modal:** focus the dialog wrapper on present so screen readers can enter the modal ([#31260](https://github.com/ionic-team/ionic-framework/issues/31260)) ([6251eb8](https://github.com/ionic-team/ionic-framework/commit/6251eb85db0e5b43b9e09604248dc8451e1664c0)) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + + +### Bug Fixes + +* **tab-bar:** fire tab change events on tab click ([#31262](https://github.com/ionic-team/ionic-framework/issues/31262)) ([44461dd](https://github.com/ionic-team/ionic-framework/commit/44461ddda5ef44030f477931dd94cce4674801a6)), closes [#30145](https://github.com/ionic-team/ionic-framework/issues/30145) + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 5e125fe6772..a7596c353cc 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **modal:** focus the dialog wrapper on present so screen readers can enter the modal ([#31260](https://github.com/ionic-team/ionic-framework/issues/31260)) ([6251eb8](https://github.com/ionic-team/ionic-framework/commit/6251eb85db0e5b43b9e09604248dc8451e1664c0)) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/core + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) diff --git a/core/package-lock.json b/core/package-lock.json index ba23de94f30..f73c4fa715e 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { "@phosphor-icons/core": "^2.1.1", diff --git a/core/package.json b/core/package.json index 488cade703f..21ca7f138b5 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "description": "Base components for Ionic", "engines": { "node": ">= 16" diff --git a/core/src/components/modal/gestures/sheet.ts b/core/src/components/modal/gestures/sheet.ts index 322bb82b84f..e9c949400a3 100644 --- a/core/src/components/modal/gestures/sheet.ts +++ b/core/src/components/modal/gestures/sheet.ts @@ -300,6 +300,13 @@ export const createSheetGesture = ( }; const onStart = (detail: GestureDetail) => { + /** + * Firefox automatically selects the header text during drag + * due to the focusable wrapper (tabindex="-1"). Remove any + * selection that may have occurred. + */ + window.getSelection()?.removeAllRanges(); + /** * If canDismiss is anything other than `true` * then users should be able to swipe down diff --git a/core/src/components/modal/gestures/swipe-to-close.ts b/core/src/components/modal/gestures/swipe-to-close.ts index 2b66e7eac24..d04220c88e7 100644 --- a/core/src/components/modal/gestures/swipe-to-close.ts +++ b/core/src/components/modal/gestures/swipe-to-close.ts @@ -116,6 +116,13 @@ export const createSwipeToCloseGesture = ( const onStart = (detail: GestureDetail) => { const { deltaY } = detail; + /** + * Firefox automatically selects the header text during drag + * due to the focusable wrapper (tabindex="-1"). Remove any + * selection that may have occurred. + */ + window.getSelection()?.removeAllRanges(); + /** * Get the initial scrollY value so * that we can correctly reset the scrollY diff --git a/core/src/components/modal/modal.common.scss b/core/src/components/modal/modal.common.scss index 5f1d17105a9..dfe405a2ba6 100644 --- a/core/src/components/modal/modal.common.scss +++ b/core/src/components/modal/modal.common.scss @@ -79,6 +79,14 @@ ion-backdrop { z-index: 10; } +/** + * The wrapper receives programmatic focus for screen readers but should not + * show a visible focus ring, which is meant only for keyboard navigation. + */ +.modal-wrapper { + outline: none; +} + .modal-shadow { position: absolute; diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index aaf26035fca..fc3a62281f7 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -1677,10 +1677,17 @@ export class Modal implements ComponentInterface, OverlayInterface { same element. They must also be set inside the shadow DOM otherwise ion-button will not be highlighted when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134 + + tabIndex={-1} is required so present() can move focus to this + element (which carries the dialog role) instead of the role-less + host. role="dialog" alone does not make an element focusable, so + without the tabindex focus() would be a no-op and screen readers + may not properly announce the dialog and its content when it opens. */ role="dialog" {...inheritedAttributes} aria-modal="true" + tabIndex={-1} class="modal-wrapper ion-overlay-wrapper" part="content" ref={(el) => (this.wrapperEl = el)} diff --git a/core/src/components/modal/test/a11y/modal.e2e.ts b/core/src/components/modal/test/a11y/modal.e2e.ts index 5aef2cda0d8..0cacc470903 100644 --- a/core/src/components/modal/test/a11y/modal.e2e.ts +++ b/core/src/components/modal/test/a11y/modal.e2e.ts @@ -19,5 +19,22 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => const results = await new AxeBuilder({ page }).analyze(); expect(results.violations).toEqual([]); }); + + // The focused wrapper must not show a focus ring when opened via keyboard. + test('should not render a focus ring on the wrapper when presented via keyboard', async ({ page }) => { + await page.goto(`/src/components/modal/test/a11y`, config); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const button = page.locator('#open-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + // Open with the keyboard so :focus-visible applies to the wrapper. + await button.focus(); + await page.keyboard.press('Enter'); + await ionModalDidPresent.next(); + + await expect(wrapper).toBeFocused(); + await expect(wrapper).toHaveCSS('outline-style', 'none'); + }); }); }); diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index f4b6fd83f02..2f28c0cafdb 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -910,7 +910,29 @@ export const present = async ( * to the overlay container. */ if (overlay.keyboardClose && (document.activeElement === null || !overlay.el.contains(document.activeElement))) { - overlay.el.focus(); + /** + * Some overlays (e.g. modal) put the dialog role and accessible label + * on the `.ion-overlay-wrapper` instead of the host. Screen readers + * need focus on the element with `role="dialog"` to properly announce + * and navigate the dialog. + * + * We only target wrappers with `tabindex`, since `role="dialog"` alone + * does not make an element focusable. If no focusable dialog wrapper + * exists (e.g. picker-legacy), we fall back to the host. + */ + const overlayWrapper = getElementRoot(overlay.el).querySelector('[role="dialog"][tabindex]'); + const focusTarget = overlayWrapper ?? overlay.el; + /** + * `preventScroll` keeps this a pure focus move so the viewport does not + * jump when the wrapper is partially off-screen (e.g. a sheet modal). + * Guard the options call so an older engine that mishandles it can never + * reject present(); we fall back to a plain focus() in that case. + */ + try { + focusTarget.focus({ preventScroll: true }); + } catch { + focusTarget.focus(); + } } /** diff --git a/core/src/utils/test/overlays/overlays.e2e.ts b/core/src/utils/test/overlays/overlays.e2e.ts index ebe7d25a273..de73fd2f011 100644 --- a/core/src/utils/test/overlays/overlays.e2e.ts +++ b/core/src/utils/test/overlays/overlays.e2e.ts @@ -421,5 +421,87 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => // verify focus is in correct location await expect(input).toBeFocused(); }); + + // Focus the role="dialog" wrapper on present so screen readers can enter. + test('should focus the modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` + + Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => el.present()); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); + + test('should focus the sheet modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` + + Sheet Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => el.present()); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); + + test('should focus the card modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` +
+ Root Content +
+ + Card Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => { + el.presentingElement = document.querySelector('.ion-page')!; + return el.present(); + }); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); }); }); diff --git a/core/src/utils/test/playwright/drag-element.ts b/core/src/utils/test/playwright/drag-element.ts index 81f6f9a6c9e..5b4a4d8066a 100644 --- a/core/src/utils/test/playwright/drag-element.ts +++ b/core/src/utils/test/playwright/drag-element.ts @@ -48,6 +48,12 @@ export const dragElementBy = async ( await page.mouse.down(); + // Firefox treats focusable elements (tabindex="-1") as draggable text and + // initiates text selection on mouse.down(). In Playwright, this selection + // locks in before the gesture detector fires, blocking pointer events. + // Clearing it here allows the drag gesture to proceed normally. + await page.evaluate(() => window.getSelection()?.removeAllRanges()); + // Drag the element. await moveElement(page, startX, startY, dragByX, dragByY, steps); diff --git a/lerna.json b/lerna.json index c1ff80a0f28..c1999229e99 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "core", "packages/*" ], - "version": "8.8.13" + "version": "8.8.15" } \ No newline at end of file diff --git a/packages/angular-server/CHANGELOG.md b/packages/angular-server/CHANGELOG.md index 3238fb0800f..4ccbf22bbce 100644 --- a/packages/angular-server/CHANGELOG.md +++ b/packages/angular-server/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **angular-server:** fallback to scoped+annotations when SSR DOM lacks attachShadow ([#30967](https://github.com/ionic-team/ionic-framework/issues/30967)) ([ae6911f](https://github.com/ionic-team/ionic-framework/commit/ae6911f6c8d46467ae54114295688bbba5ccbf5e)), closes [#29751](https://github.com/ionic-team/ionic-framework/issues/29751) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/angular-server + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/angular-server diff --git a/packages/angular-server/package-lock.json b/packages/angular-server/package-lock.json index 313f8b6131d..399e46b387c 100644 --- a/packages/angular-server/package-lock.json +++ b/packages/angular-server/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular-server", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/angular-server", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13" + "@ionic/core": "^8.8.15" }, "devDependencies": { "@angular-eslint/eslint-plugin": "^16.0.0", @@ -1031,9 +1031,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -7309,9 +7309,9 @@ "dev": true }, "@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "requires": { "@stencil/core": "4.43.5", "ionicons": "^8.0.13", diff --git a/packages/angular-server/package.json b/packages/angular-server/package.json index bce1b7a50e6..ee10b028ddb 100644 --- a/packages/angular-server/package.json +++ b/packages/angular-server/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular-server", - "version": "8.8.13", + "version": "8.8.15", "description": "Angular SSR Module for Ionic", "keywords": [ "ionic", @@ -62,6 +62,6 @@ }, "prettier": "@ionic/prettier-config", "dependencies": { - "@ionic/core": "^8.8.13" + "@ionic/core": "^8.8.15" } } diff --git a/packages/angular-server/src/ionic-server-module.ts b/packages/angular-server/src/ionic-server-module.ts index 72b53de322e..f2d65755a6a 100644 --- a/packages/angular-server/src/ionic-server-module.ts +++ b/packages/angular-server/src/ionic-server-module.ts @@ -20,8 +20,17 @@ export class IonicServerModule {} export function hydrateIonicComponents(doc: any, appId: any) { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types return () => { + const supportsNativeAttachShadow = + typeof doc?.createElement?.('div')?.attachShadow === 'function'; + return hydrateDocument(doc, { - clientHydrateAnnotations: false, + // Fallback for SSR DOMs (e.g. Domino) that do not implement attachShadow. + ...(supportsNativeAttachShadow + ? { clientHydrateAnnotations: false } + : { + serializeShadowRoot: 'scoped', + clientHydrateAnnotations: true, + }), excludeComponents: [ // overlays 'ion-action-sheet', diff --git a/packages/angular/CHANGELOG.md b/packages/angular/CHANGELOG.md index 29461963d67..20ab7d5ba4c 100644 --- a/packages/angular/CHANGELOG.md +++ b/packages/angular/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/angular + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/angular + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/angular diff --git a/packages/angular/package-lock.json b/packages/angular/package-lock.json index 627a6a54dac..adbea154935 100644 --- a/packages/angular/package-lock.json +++ b/packages/angular/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" @@ -1398,9 +1398,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/angular/package.json b/packages/angular/package.json index 97844662282..5eb59586f14 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "description": "Angular specific wrappers for @ionic/core", "keywords": [ "ionic", @@ -48,7 +48,7 @@ } }, "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" diff --git a/packages/docs/CHANGELOG.md b/packages/docs/CHANGELOG.md index 69a91d7e43b..15c703ffa25 100644 --- a/packages/docs/CHANGELOG.md +++ b/packages/docs/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/docs + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/docs + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/docs diff --git a/packages/docs/package-lock.json b/packages/docs/package-lock.json index 32b6c60cc7f..2f96d120cbd 100644 --- a/packages/docs/package-lock.json +++ b/packages/docs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT" } } diff --git a/packages/docs/package.json b/packages/docs/package.json index 5eb602d6513..262e89331b3 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "description": "Pre-packaged API documentation for the Ionic docs.", "main": "core.json", "types": "core.d.ts", diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md index cf601872233..119692c6d83 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/react-router + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/react-router + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/react-router diff --git a/packages/react-router/package-lock.json b/packages/react-router/package-lock.json index 02d00bfb432..9031a7d4ea7 100644 --- a/packages/react-router/package-lock.json +++ b/packages/react-router/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react-router", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/react-router", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/react": "^8.8.13", + "@ionic/react": "^8.8.15", "tslib": "*" }, "devDependencies": { @@ -238,9 +238,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -418,12 +418,12 @@ } }, "node_modules/@ionic/react": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.13.tgz", - "integrity": "sha512-xKevvpmTfi2ZtOcmwEsw3EE6fm+TqKYIHKvgkIwAUz/bnRcMmGA9b474WxJcLQ5Twv8ynj/C1iDQcDA+jR0/pw==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.15.tgz", + "integrity": "sha512-8bjys95dICAfJMwA0iuKIYfg5pbz2lY56eQpIG6In+796PvMNVXE9eFLhIZ15jjpRE1O/HZHxO2OFV/pL3NVdA==", "license": "MIT", "dependencies": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "ionicons": "^8.0.13", "tslib": "*" }, @@ -4178,9 +4178,9 @@ "dev": true }, "@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "requires": { "@stencil/core": "4.43.5", "ionicons": "^8.0.13", @@ -4284,11 +4284,11 @@ "requires": {} }, "@ionic/react": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.13.tgz", - "integrity": "sha512-xKevvpmTfi2ZtOcmwEsw3EE6fm+TqKYIHKvgkIwAUz/bnRcMmGA9b474WxJcLQ5Twv8ynj/C1iDQcDA+jR0/pw==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.15.tgz", + "integrity": "sha512-8bjys95dICAfJMwA0iuKIYfg5pbz2lY56eQpIG6In+796PvMNVXE9eFLhIZ15jjpRE1O/HZHxO2OFV/pL3NVdA==", "requires": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "ionicons": "^8.0.13", "tslib": "*" } diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 0630a327290..818393ac6b9 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react-router", - "version": "8.8.13", + "version": "8.8.15", "description": "React Router wrapper for @ionic/react", "keywords": [ "ionic", @@ -36,7 +36,7 @@ "dist/" ], "dependencies": { - "@ionic/react": "^8.8.13", + "@ionic/react": "^8.8.15", "tslib": "*" }, "peerDependencies": { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 61282f1918e..e0e3c9aeba1 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/react + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + + +### Bug Fixes + +* **tab-bar:** fire tab change events on tab click ([#31262](https://github.com/ionic-team/ionic-framework/issues/31262)) ([44461dd](https://github.com/ionic-team/ionic-framework/commit/44461ddda5ef44030f477931dd94cce4674801a6)), closes [#30145](https://github.com/ionic-team/ionic-framework/issues/30145) + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/react diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index 1d6143adc8e..c7d267d5894 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "ionicons": "^8.0.13", "tslib": "*" }, @@ -736,9 +736,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/react/package.json b/packages/react/package.json index 10f109c5d21..64af2f66975 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "description": "React specific wrapper for @ionic/core", "keywords": [ "ionic", @@ -40,7 +40,7 @@ "css/" ], "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "ionicons": "^8.0.13", "tslib": "*" }, diff --git a/packages/react/src/components/navigation/IonTabBar.tsx b/packages/react/src/components/navigation/IonTabBar.tsx index 124b00f6990..ab1db62f197 100644 --- a/packages/react/src/components/navigation/IonTabBar.tsx +++ b/packages/react/src/components/navigation/IonTabBar.tsx @@ -224,12 +224,20 @@ class IonTabBarUnwrapped extends React.PureComponent { /** * Verifies that tabs with similar route prefixes (e.g., /home, /home2, /home3) * correctly select the matching tab instead of the first prefix match. - * + * * @see https://github.com/ionic-team/ionic-framework/issues/30448 */ describe('Similar Route Prefixes', () => { @@ -58,7 +58,11 @@ describe('IonTabs', () => { describe('Without IonRouterOutlet', () => { beforeEach(() => { - cy.visit('/tabs-basic'); + cy.visit('/tabs-basic', { + onBeforeLoad(win) { + cy.spy(win.console, 'log').as('consoleLog'); + }, + }); }); it.skip('should show correct tab when clicking the tab button', () => { @@ -83,5 +87,12 @@ describe('IonTabs', () => { cy.url().should('include', '/tabs-basic'); }); + + it('should fire tab change events on tab click', () => { + cy.get('ion-tab-button[tab="tab2"]').click(); + + cy.get('@consoleLog').should('be.calledWith', 'onIonTabsWillChange', 'tab2'); + cy.get('@consoleLog').should('be.calledWith', 'onIonTabsDidChange:', 'tab2'); + }); }); }); diff --git a/packages/vue-router/CHANGELOG.md b/packages/vue-router/CHANGELOG.md index 9697a53d608..3f626505934 100644 --- a/packages/vue-router/CHANGELOG.md +++ b/packages/vue-router/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/vue-router + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/vue-router + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/vue-router diff --git a/packages/vue-router/package-lock.json b/packages/vue-router/package-lock.json index 5c7438a49f3..ef1cc487fdd 100644 --- a/packages/vue-router/package-lock.json +++ b/packages/vue-router/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/vue-router", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/vue-router", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/vue": "^8.8.13" + "@ionic/vue": "^8.8.15" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", @@ -673,9 +673,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -868,12 +868,12 @@ } }, "node_modules/@ionic/vue": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.13.tgz", - "integrity": "sha512-PgpuoQInVBAmBwn12Wg7nvZ471khG++3UGlEsOAFZ6D6BFEvv8OMz90MTE5j6gnT//lzP2GIs/msG+LS8FV5vQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.15.tgz", + "integrity": "sha512-WYM51Qlh1PES6Xst+085ueGj4iars2AhBnTboQBLxS9knU6hHQ90/5/pNjOl3WyFkmWV7/kL8iQaR7o+qESLxQ==", "license": "MIT", "dependencies": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" } @@ -8044,9 +8044,9 @@ "dev": true }, "@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "requires": { "@stencil/core": "4.43.5", "ionicons": "^8.0.13", @@ -8159,11 +8159,11 @@ "requires": {} }, "@ionic/vue": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.13.tgz", - "integrity": "sha512-PgpuoQInVBAmBwn12Wg7nvZ471khG++3UGlEsOAFZ6D6BFEvv8OMz90MTE5j6gnT//lzP2GIs/msG+LS8FV5vQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.15.tgz", + "integrity": "sha512-WYM51Qlh1PES6Xst+085ueGj4iars2AhBnTboQBLxS9knU6hHQ90/5/pNjOl3WyFkmWV7/kL8iQaR7o+qESLxQ==", "requires": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" } diff --git a/packages/vue-router/package.json b/packages/vue-router/package.json index 7dc3bb4f378..148fe0aa14a 100644 --- a/packages/vue-router/package.json +++ b/packages/vue-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue-router", - "version": "8.8.13", + "version": "8.8.15", "description": "Vue Router integration for @ionic/vue", "scripts": { "test.spec": "jest", @@ -44,7 +44,7 @@ }, "homepage": "https://github.com/ionic-team/ionic-framework#readme", "dependencies": { - "@ionic/vue": "^8.8.13" + "@ionic/vue": "^8.8.15" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", diff --git a/packages/vue/CHANGELOG.md b/packages/vue/CHANGELOG.md index b9d622271a2..060691a3ca7 100644 --- a/packages/vue/CHANGELOG.md +++ b/packages/vue/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/vue + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/vue + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/vue diff --git a/packages/vue/package-lock.json b/packages/vue/package-lock.json index 838a65c2899..07a3e46add3 100644 --- a/packages/vue/package-lock.json +++ b/packages/vue/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" }, @@ -222,9 +222,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/vue/package.json b/packages/vue/package.json index db6da908fe7..68f9e44cdea 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "description": "Vue specific wrapper for @ionic/core", "scripts": { "eslint": "eslint src", @@ -68,7 +68,7 @@ "vue-router": "^4.0.16" }, "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" },