๐ŸŸข Link


Basic

NLink is a custom NuxtLink component that provides additional functionality for rendering links to pages in your application.

PropTypeDescription
inactiveClassstringThe class to apply when the link is inactive.
exactbooleanTrigger the link active class only on exact matches of the path.
exactQuerybooleanTrigger the link active class only on exact matches of the query.
exactHashbooleanTrigger the link active class only on exact matches of the hash.

You can also use any prop provided by the NuxtLink component.

You can take a look and click at examples of different usage below:

<template>
  <div class="flex gap-4">
    <NLink
      to="/components/link"
      active-class="text-success"
    >
      Active Link
    </NLink>

    <NLink
      to="/components/link/"
      exact-active-class="text-lime"
      exact
    >
      Exact Active Link
    </NLink>

    <NLink
      to="https://github.com/una-ui/una-ui"
      target="_blank"
      inactive-class="text-gray"
    >
      Inactive Link
    </NLink>

    <NLink
      to="/components/link?search=something"
      active-class="text-warning"
      exact-query
    >
      Exact query
    </NLink>

    <NLink
      to="/components/link#something"
      active-class="text-pink"
      exact-hash
    >
      Exact Hash
    </NLink>
  </div>
</template>

Props

import type { NuxtLinkProps } from 'nuxt/app'

export interface NLinkProps extends NuxtLinkProps {
  /**
   * Manually enable/disable the exact match
   *
   * @default false
   */
  exact?: boolean
  /**
   * Manually enable/disable the exact match for the query string
   *
   * @default false
   */
  exactQuery?: boolean
  /**
   * Manually enable/disable the exact match for the hash
   *
   * @default false
   */
  exactHash?: boolean

  /**
   * Active classes to apply when the link is inactive
   *
   * @example 'text-primary'
   */
  inactiveClass?: string

  /**
   * Useful in combination with `NavLink` to apply the active class to the parent element
   *
   */
  navLinkActive?: string

  /**
   * Useful in combination with `NavLink` to apply the inactive class to the parent element
   */
  navLinkInactive?: string
}

Presets

type LinkPrefix = 'link'

export const staticLink: Record<LinkPrefix, string> = {
  // base
  link: '',
}

export const dynamicLink: [RegExp, (params: RegExpExecArray) => string][] = [
  // dynamic preset
]

export const link = [
  ...dynamicLink,
  staticLink,
]

Component

<script lang="ts">
import type { PropType } from 'vue'
import type { NLinkProps } from '../../types'
import { NuxtLink } from '#components'
import { isEqual } from 'ohash'
import { defineComponent } from 'vue'

export default defineComponent({
  inheritAttrs: false,
  props: {
    ...NuxtLink.props,
    // config
    exact: {
      type: Boolean as PropType<NLinkProps['exact']>,
      default: false,
    },
    exactQuery: {
      type: Boolean as PropType<NLinkProps['exactQuery']>,
      default: false,
    },
    exactHash: {
      type: Boolean as PropType<NLinkProps['exactHash']>,
      default: false,
    },

    // styling
    inactiveClass: {
      type: String as PropType<NLinkProps['inactiveClass']>,
      default: undefined,
    },

    // preset
    navLinkActive: {
      type: String as PropType<NLinkProps['navLinkActive']>,
      default: undefined,
    },
    navLinkInactive: {
      type: String as PropType<NLinkProps['navLinkInactive']>,
      default: undefined,
    },
  },
  setup(props: any) {
    function resolveLinkClass(route: any, $route: any, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }): string | null {
      if (props.exactQuery && !isEqual(route.query, $route.query))
        return props.inactiveClass

      if (props.exactHash && !isEqual(route.hash, $route.hash))
        return props.inactiveClass

      if (props.exact && isExactActive)
        return props.exactActiveClass

      if (!props.exact && isActive)
        return props.activeClass

      return props.inactiveClass
    }

    function resolveNavLinkActive(route: any, $route: any, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }): string | null {
      if (props.exactQuery && !isEqual(route.query, $route.query))
        return null

      if (props.exactHash && !isEqual(route.hash, $route.hash))
        return null

      if (props.exact && isExactActive)
        return props.navLinkActive

      if (!props.exact && isActive)
        return props.navLinkActive

      return null
    }

    function resolveNavLinkInactive(route: any, $route: any, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }): string | null {
      if (props.exactQuery && !isEqual(route.query, $route.query))
        return props.navLinkInactive

      if (props.exactHash && !isEqual(route.hash, $route.hash))
        return props.navLinkInactive

      if ((!props.exact && isActive) || (props.exact && isExactActive))
        return null

      return props.navLinkInactive
    }

    return {
      resolveLinkClass,
      resolveNavLinkActive,
      resolveNavLinkInactive,
    }
  },
})
</script>

<template>
  <!-- eslint-disable vue/no-template-shadow -->
  <NuxtLink
    v-slot="{ route, href, target, rel, navigate, isActive, isExactActive, isExternal, exact }"
    v-bind="$props"
    custom
  >
    <a
      v-bind="$attrs"
      :href="href"
      :rel="rel"
      :target="target"
      :class="resolveLinkClass(route, $route, { isActive, isExactActive })"
      :nav-link-active="resolveNavLinkActive(route, $route, { isActive, isExactActive })"
      :nav-link-inactive="resolveNavLinkInactive(route, $route, { isActive, isExactActive })"
      @click="(e) => !isExternal && navigate(e)"
    >
      <slot v-bind="{ isActive: exact ? isExactActive : isActive }" />
    </a>
  </NuxtLink>
</template>