Skip to content

fix(angular): honor modifier-click on routerLink - #31230

Merged
ShaneK merged 2 commits into
mainfrom
fix/angular-routerlink-modifier-click
Jun 18, 2026
Merged

ShaneK merged 2 commits into
mainfrom
fix/angular-routerlink-modifier-click

Conversation

@ShaneK

@ShaneK ShaneK commented Jun 17, 2026 •

Copy link
Copy Markdown
Member

Issue number: resolves #26394


What is the current behavior?

When routerLink is applied to a non-anchor Ionic component (ion-item, ion-button), RouterLinkDelegateDirective always routes in-app on click. A ctrl/meta/shift/alt click, or a host with target="_blank", gets swallowed by the in-app navigation, so the browser never opens the link in a new tab. A plain <a routerLink> honors these intents, but the Ionic delegate doesn't, even though these components render a native anchor in their shadow DOM that's capable of the native new-tab behavior.

What is the new behavior?

RouterLinkDelegateDirective now adds a capture-phase click listener so it runs before Angular's RouterLink handler and the directive's own bubble-phase onClick. When the click should be handled natively (a ctrl/meta/shift/alt modifier is held, or the host target is set to anything other than _self), it calls stopImmediatePropagation() to cancel the in-app navigation but leaves preventDefault alone, so the shadow-DOM anchor can still open the tab. This mirrors the modifier set Angular's own RouterLink guards on. Normal clicks are unaffected and continue to navigate in-app. The listener is removed in ngOnDestroy.

Does this introduce a breaking change?

  • Yes
  • No

Other information

This supersedes #28976 by @j-oppenhuis, which first surfaced the target and modifier-click gap. Credited as co-author below.

To verify manually in the Angular preview, ctrl/cmd-click the two ion-item rows (a plain one and a target="_blank" one) and confirm each opens a new tab instead of navigating in place:
https://ionic-framework-git-fix-angular-routerlink-modifi-896c58-ionic1.vercel.app/angular/standalone/router-link

If you compare that against the main version of the same component, you'll be able to see how it's fixed:
https://ionic-framework-git-main-ionic1.vercel.app/angular/standalone/router-link

Co-authored-by: Jelle Oppenhuis jelle@siyou.nl

@ShaneK
ShaneK requested a review from a team as a code owner June 17, 2026 20:11
@ShaneK
ShaneK requested a review from OS-jacobbell June 17, 2026 20:11
@vercel

vercel Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Jun 18, 2026 3:36pm

Request Review

@github-actions github-actions Bot added the package: angular @ionic/angular package label Jun 17, 2026

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, please provide co-author for the associated PR

@ShaneK
ShaneK added this pull request to the merge queue Jun 18, 2026
Merged via the queue into main with commit 2ac9851 Jun 18, 2026
53 checks passed
@ShaneK
ShaneK deleted the fix/angular-routerlink-modifier-click branch June 18, 2026 16:25
HappyKnuckles pushed a commit to HappyKnuckles/ionic-framework that referenced this pull request Oct 3, 2026
Issue number: resolves ionic-team#26394

---------

## What is the current behavior?

When `routerLink` is applied to a non-anchor Ionic component
(`ion-item`, `ion-button`), `RouterLinkDelegateDirective` always routes
in-app on click. A ctrl/meta/shift/alt click, or a host with
`target="_blank"`, gets swallowed by the in-app navigation, so the
browser never opens the link in a new tab. A plain `<a routerLink>`
honors these intents, but the Ionic delegate doesn't, even though these
components render a native anchor in their shadow DOM that's capable of
the native new-tab behavior.

## What is the new behavior?

`RouterLinkDelegateDirective` now adds a capture-phase click listener so
it runs before Angular's `RouterLink` handler and the directive's own
bubble-phase `onClick`. When the click should be handled natively (a
ctrl/meta/shift/alt modifier is held, or the host `target` is set to
anything other than `_self`), it calls `stopImmediatePropagation()` to
cancel the in-app navigation but leaves `preventDefault` alone, so the
shadow-DOM anchor can still open the tab. This mirrors the modifier set
Angular's own `RouterLink` guards on. Normal clicks are unaffected and
continue to navigate in-app. The listener is removed in `ngOnDestroy`.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

## Other information

This supersedes ionic-team#28976 by @j-oppenhuis, which first surfaced the target
and modifier-click gap. Credited as co-author below.

To verify manually in the Angular preview, ctrl/cmd-click the two
`ion-item` rows (a plain one and a `target="_blank"` one) and confirm
each opens a new tab instead of navigating in place:

https://ionic-framework-git-fix-angular-routerlink-modifi-896c58-ionic1.vercel.app/angular/standalone/router-link

If you compare that against the main version of the same component,
you'll be able to see how it's fixed:

https://ionic-framework-git-main-ionic1.vercel.app/angular/standalone/router-link

Co-authored-by: Jelle Oppenhuis <jelle@siyou.nl>

This branch was successfully deployed

1 active deployment
Preview — d86e78cd Deployed Jun 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: angular @ionic/angular package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: ion-item href prop causes hard refresh when clicked, and routerLink prop disallows ctrl+click to open in new tab

2 participants