I am trying to have all external links on my website raise a confirm saying "You are being redirected to an external site." I know how to write the JS to check for if a link is external and how to raise the confirm, but is there a way I can apply this to every link in my site without going through individually? The links will always have the format <a href=URL> Link </a>
. An angular script would check if the URL
subdomain is the same as my site, and if not it will add onclick=return confirm('You will now be redirected to an exteral site')
and target="_blank"
to the link HTML.

- 55
- 1
- 10
-
Yes, what have you tried? – Luca Kiebel Jun 08 '18 at 14:24
-
@Luca I'm really not sure where to begin. I've tried googling, but haven't found anything applicable yet. – laminarflow Jun 08 '18 at 14:26
-
As it is right now, I think your question may be too broad. I think your next step is to define a context of places where you want to protect users. There are a **lot** of ways to change pages. You can control some, wrapping `` clicks for example, but it might get irritating if your footer links keep triggering the warning. Is your site user content based? Do you only want to warn about those? Are users limited to only ``s in posts? What is the context? – zero298 Jun 08 '18 at 14:28
-
@zero298 I've updated with a bit more information. – laminarflow Jun 08 '18 at 14:31
-
If the links that you want to trigger the warning have that directive, then what isn't working? Do you want to extend this protection to links that don't have that directive? – zero298 Jun 08 '18 at 14:35
-
@zero298 Yes, I want this to extend to all links in my site. It is quite large and would be a pain to go through and edit every single one. This would also make adding new external links a bit easier. – laminarflow Jun 08 '18 at 14:36
-
You'd have to write a directive to intercept every anchor and evaluate its URL to determine whether it's external. – isherwood Jun 08 '18 at 14:39
-
That would be nice to have something like `document.querySelectorAll('a').filter(a => isExternal(a.src)).forEach(e => e.addEventListener('click', warnTheyAreLeaving))`. I wasn't much inspired for the last function name but you would : Select All links Filter them if they are external (isExternal would check if the src attribute of a tags have a different domain name than your) and add an event listener to each of them on click, warn them they are leaving. I have absolutely no idea about how to implement that in angular though – Zyigh Jun 08 '18 at 14:40
-
I have never understood why people think that this is a good idea unless your goal is to encourage your visitors to never return to your website. – zzzzBov Jun 08 '18 at 14:50
4 Answers
As you already said, this can be achieved by using confirm
onclick, you can easily add an EventListener to all a
Elements that are external (l.hostname !== location.hostname
) in your page and only redirect after the user accepts the message, just like so:
Array.from(document.querySelectorAll("a")).filter(l => l.hostname !== location.hostname).forEach(el => el.addEventListener("click", evtL));
function evtL(e) {
if (confirm("Are you sure you want to leave the page?")) {
return; //redirect
} else {
e.preventDefault();
return false; //don't redirect
}
}
<a href="/foo/bar">internal</a>
<a href="https://example.com">external</a>
<a href="https://stacksnippets.net/js">also internal</a>

- 9,790
- 7
- 29
- 44
-
I was writing my comment at the same time you were posting you're answer so I couldn't see it. Why not filtering the result of the querySelectorAll so not all links have an eventListener, but only the ones who need to have one ? – Zyigh Jun 08 '18 at 14:49
-
You're right, that would be more efficient, thanks for the suggestions – Luca Kiebel Jun 08 '18 at 14:50
-
1
Since you are using Angular.js, I would recommend taking a look at how they work with <a>
since they already have a directive applied to all <a>
to make ngHref
work. The source would be here: <a>
directive.
The basic idea is to put the logic that you use to change the href
to the warning or display a modal or whatever in the element.on('click', function(event) {...})
.
Because Angular.js already defined an <a>
directive, you may need to fiddle with the priority
of your directive so that you don't accidentally break the way Angular fiddles with <a>
.
The directive would look something like this:
// Logic that dictactes whether the URL should show a warning
function isSuspectUrl(l) {
return false;
}
const app = angular
.module("aWarn", [])
.directive("a", function() {
return {
restrict: "E",
compile: function(el, attr) {
element.on("click", function(e) {
if (isSuspectUrl(attr.href)) {
// Logic that would display a warning
}
});
}
}
});

- 25,467
- 10
- 75
- 100
- It can be achieved by the regex matching.
- Instead of adding multiple event listeners, single event listener can be added on the
document
object and detect the external links as follows. It will give more efficiency.
For reference, Handling events for multiple elements in a single listener
var regexp = /https?:\/\/(www.){0,1}((?:[\w\d-]+\.)+[\w\d]{2,})/i;
function isExternal(url)
{
return regexp.exec(location.href)[2] !== regexp.exec(url)[2];
}
document.addEventListener("click",function(){
if(event.target.tagName.toLowerCase()==="a")
{
if(isExternal(event.target.href))
{
if(confirm("Redirecting to an external site...."))
{
console.log("Going to external site...");
return;
}
else
{
event.preventDefault();
return;
}
}
else
{
console.log("Internal URL Clicked.")
}
}
});
<a href="https://www.google.com" target="_blank">External Site 1</a> - https://www.google.com<br>
<a href="https://www.stackoverflow.com" target="_blank">External Site 2</a> - https://www.stackoverflow.com<br>
<a href="http://www.facebook.com" target="_blank">External Site 3</a> - http://www.facebook.com (Using HTTP)<br>
<a href="http://www.stacksnippets.net" target="_blank">Internal Site (Using HTTP)</a> - http://www.stacksnippets.net<br>
<a href="http://stacksnippets.net" target="_blank">Internal Site (without www.)</a> - http://stacksnippets.net<br>
<a href="/path/to/something" target="_blank">Internal reference</a> - /path/to/something (Internal reference)<br>
Thanks @pseudosavant for the regex.
Though @Luca's answer works, the hostname
is not supported in IE, Safari and Opera. Browser Compatibility for reference.

- 7,927
- 1
- 33
- 42
-
Thank you. I ended up using my own logic instead of your regex, but it worked. How would I also add `target="blank"` if the user does confirm he or she wants to leave? – laminarflow Jun 08 '18 at 16:20
-
Couldn’t get you. You mean if the user confirms, you want to direct the user to another page in a new tab ? – Vignesh Raja Jun 08 '18 at 17:06
-
-
It already does, right ? Its target=“_blank” (with an underscore). – Vignesh Raja Jun 08 '18 at 17:21
-
I would like to be able to not have to specify in the original html – laminarflow Jun 08 '18 at 17:25
2021 version
- es2015+
- Works with SPA
- Handles local links that look external
- Subdomains support
const baseUrl = window.location.origin;
const absoluteUrlRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
const isAbsoluteUrl = (url) => absoluteUrlRegex.test(url);
const isLocalUrl = (url) => url.startsWith(baseUrl) || !isAbsoluteUrl(url);
// https://gist.github.com/ -> github.com
// https://stackoverflow.com/ -> stackoverflow.com
const getDomain = (url) => {
const urlInstance = new URL(url);
const dividedUrl = urlInstance.hostname.split('.');
const urlDomainsCount = dividedUrl.length;
return urlDomainsCount === 2
? urlInstance.hostname
: `${dividedUrl[urlDomainsCount - 2]}.${dividedUrl[urlDomainsCount - 1]}`;
};
// example whitelist
const whitelist = [
'twitter.com',
'github.com',
];
// url has same domain or whitelisted
const isWhitelistedUrl = (url) => {
const domain = getDomain(url);
return domain === window.location.hostname || whitelist.includes(domain);
};
// bind listener
const confirmExternalLinks = (confirmationFn) => {
document.addEventListener('click', async (e) => {
const linkElement = e.target.closest('a');
if (!linkElement) return;
const link = linkElement.getAttribute('href');
if (isLocalUrl(link) || isWhitelistedUrl(link)) return;
e.preventDefault();
const confirmation = await confirmationFn(link);
if (confirmation) window.open(link);
});
};
// tip: replace confirmationFn with your custom handler which returns Promise
confirmExternalLinks((link) => confirm(`Proceed to ${link}?`));
<a target="_blank" href="https://stacksnippets.net/">https://stacksnippets.net/</a> is local for this snippet iframe
<br>
<a target="_blank" href="https://twitter.com/">https://twitter.com/</a> is whitelisted
<br>
<a target="_blank" href="https://developer.mozilla.org/">https://developer.mozilla.org/</a> is external

- 356
- 3
- 10