nuxt: nuxt-link does not resolve inside an as prop

Environment

  • Operating System: Linux
  • Node Version: v16.14.2
  • Nuxt Version: 3.0.0-27501460.04a72f8
  • Package Manager: npm@8.5.5
  • Builder: vite
  • User Config: css, buildModules, vite, build
  • Runtime Modules: -
  • Build Modules: @pinia/nuxt@0.1.8

Reproduction

Code:

<DisclosureButton as="nuxt-link" to="/dashboard" class="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100">
  Go to dashboard
</DisclosureButton>

HTML:

<nuxt-link disabled="false" to="/dashboard" class="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100">
  Go to dashboard
</nuxt-link>

Describe the bug

This is not exactly a bug… But if it can be done somehow. The expected result would be the same as if I passed the tag ‘button’.

Example: Code:

<DisclosureButton as="button" to="/dashboard" class="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100">
  Go to dashboard
</DisclosureButton>

HTML:

<button type="button" to="/dashboard" class="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100">
  Go to dashboard
</button>

Additional context

No response

Logs

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

I’m guessing it just can’t resolve the button, since components are more “just in time” imports now. Try this:

<template>
    <DisclosureButton :as="NuxtLink" to="/dashboard" class="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100">
        Go to dashboard
    </DisclosureButton>
</template>

<script lang="ts" setup>
    const NuxtLink = resolveComponent('nuxt-link');
</script>

I do realise this discussion might not be specifically Nuxt related and is more related to Headless UI with Nuxt. @John-Church that is what I found too. I could use :as=NuxtLink successfully to render but it wouldn’t close the DisclosurePanel when activated.

So I swapped out each DisclosureButton with a NuxtLink and added a @click handler to the container that holds those links. The @click handler simply calls close() manually and then every works fine. This is mentioned in HeadlessUI docs for manually closing the panel.

It looks something like this:

<DisclosurePanel class="sm:hidden" v-slot="{ close }">
  <div @click="close()">
    <NuxtLink to="/">Home</NuxtLInk>
  </div>
</DisclosurePanel>

This works great. Also has the added benefit of being able to track and style the active link in the menu as well. I used a custom component for this something like:

export default defineNuxtLink({
    componentName: 'NavbarMobileNuxtLink',
    exactActiveClass: 'text-indigo-700 border-indigo-500 bg-indigo-50'
})

@skaaptjop I was also confused- It looks like the answer is in danielroe’s comment above: https://stackblitz.com/edit/github-a8clb2-xfuz83

Basically, add const NuxtLink = resolveComponent('nuxt-link'); to your <setup> and then use :as="NuxtLink" (don’t omit the “:”.) Like this:

<DisclosureButton
  :as="NuxtLink"
  to="/about"
>
  About
</DisclosureButton>

I just solved the problem… But I have noticed one thing. If nuxt-link is in app.vue it does not include the aria-current and class exact attributes but if it is in pages/index.vue it does.

@frbuceta I’ve got the same scenario. Could I ask how you solved it?

Vue Router isn’t active unless you have a pages directory, so those attributes won’t be added

I just solved the problem… But I have noticed one thing. If nuxt-link is in app.vue it does not include the aria-current and class exact attributes but if it is in pages/index.vue it does.