How to open external links in a new window with VueJS, vue-router and router-link

On one of my webapps I need to open external links (such as https://kerkour.com) in a new window but internal links (such as /about) with vue-router to provide a pleasant Single Page App experience.

In traditionnal HTML this is achieved with the target="_blank" rel="noopener" attributes of the a element.

Unfortunately, vue-router's RouterLink components do not support these props, so I've created a custom component. If the link's hostname is the same as the hostname of the webApp, then a RouterLink is rendered, otherwise a <a target="_blank" rel="noopener" element.

*my_link.vue

<template>
  <router-link v-if="isInternal" :to="href">
    <slot></slot>
  </router-link>
  <a v-else :href="href" target="_blank" rel="noopener">
    <slot></slot>
  </a>
</template>

<script lang="ts" setup>
import { computed, type PropType } from 'vue';

const props = defineProps({
  href: {
    type: String as PropType<string>,
    required: true,
  }
});

const isInternal = computed((): boolean => {
  if (props.href.startsWith('http')) {
    let url = null;
    try {
      url = new URL(props.href);
    } catch (err) {
      return false;
    }

    if (url.hostname != window.location.hostname) {
      return false;
    }
  }

  return true;
});
</script>

You can then use this component like that:

<template>
  <!-- ... -->
  <my-link href="/my-url" />
  <!-- ... -->
</template>

<script lang="ts" setup>
import MyLink from '@/ui/components/my_link.vue';

// ...

<script>
1 email / week to learn how to (ab)use technology for fun & profit: Programming, Hacking & Entrepreneurship.
I hate spam even more than you do. I'll never share your email, and you can unsubscribe at any time.

Tags: programming, webdev, vuejs

Want to learn Rust, Cryptography and Security? Get my book Black Hat Rust!