Skip to content

Button as router-link (please see details) #3003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jeff-hykin opened this issue Oct 21, 2019 · 4 comments
Closed

Button as router-link (please see details) #3003

jeff-hykin opened this issue Oct 21, 2019 · 4 comments

Comments

@jeff-hykin
Copy link

jeff-hykin commented Oct 21, 2019

What is the initial issue?

Using a button from a library, for example

<ui-button color="primary" style="text" :text="page.name" />

And making it behave as a router-link.

Solution 1: Why not use the tag property?

example: <router-link tag='ui-button' />

This is the first solution many seem to reach, however the color="primary" property needs to be passed to the ui-button (otherwise it is invisible in my use-case). So, the question becomes: how do I pass props to the router-link button? There does not currently seem to be a direct way to do this.

Solution 2: Why not just Wrap the Button in a router-link?

example:

<router-link tag='div' >
    <ui-button color="primary" />
</router-link>

This has a few drawbacks. When using a button from a library, the button can have margins or may change css-properties such as align-self: flex-start. When the button is wrapped, this can obviously cause problems and makes the library not behave as intended: clicking the margin of a button should not activate the button. In addition to that, the default router-link tag is the anchor tag, which means the user must go learn about the tag property and change it, lest they want all of their buttons to have underlined text. This is not an ideal programmer experience.

Solution 3: Why not use $router ?

example: <ui-button @click="()=>$router.push('about')" />

This does not behave the same as an href or router-link. For example, router-links can be opened in a new tab by pressing CMD/CTRL CLICK, however that behavior doesn't happen on an @click like the one above. This is generally a tell-tale sign of a poorly coded SPA site and is not an ideal user experience. However, making it an ideal user experience requires a non-ideal developer experience.

Solution 4: Why not create a custom component wrapper?

example: <router-link tag='custom-button'>

This would work, except for when the button needs the page name or other parent-dependent data to be passed as an attribute/property. Even if this did work, the bulkiness of this solution is problematic. Making a component redirect is incredibly basic functionality. Requiring an the creation of a wrapper component, registering it, and then attaching it to the router-link is a disproportional amount of work for such a straightforward goal.

Solution 5: Why not use href?

example: <ui-button href='page-route' />

This circumvents the process, which makes page-transition animations and other aspects fail.

Solution 6: Why not use the slots API?

example:

<router-link to="/about" v-slot="{ href, route, navigate}">
    <ui-button :href="href" @click="navigate" color="primary" style="text" :text="route.name" />
</router-link>

This is now my current solution, and is likely the best solution. However, the documentation describes the slots API as "advanced", "low-level customization", that is "primarily for library authors". Requiring devs to dive all the way into the most advanced features just for a button click is not a good experience. The slots API is very extensive, so if this was advertised as the default method of creating router-links then this likely wouldn't be as much of an issue.

What is the final issue?

This is a common task, with 5 separate unintuitive ways to poorly accomplish it, an one relatively hidden advanced but good solution. Ideally there would be one obvious standardized ideal way. As a developer, I feel like I am required to become Vue-Router expert just to make a button redirect to a new page. This is very discouraging for anyone trying to adopt the framework.

Reference

There is a question here that provides evidence of many of the challenges people have with this.

What does the proposed API look like?

Overview

The ideal solution would be to create a universal v-href and v-route property for all components similar to the way Vue handles @click on existing components.

For example <ui-button v-href='page.location' />.
This is consistent with Vue's goal of keeping the API small and intuitively close to the Javascript/HTML counterparts that developers are already familiar with.

Context

This will likely require Vue itself (and not just Vue-Router) to change. This would be designed as a full replacement of router-link component, with the intention of eventually deprecating router-link.

Details

The API for the v-href property would be identical to the current router-link "to" property. All additional prop functionality of router-link would be handled through an object on the v-route property. This would behave identically to how a router-link would behave, if the router-link were given both a tag property and (somehow) was able to pass properties/attributes to that tag.

Further implementation details will need to be discussed to ensure the intended behavior is fully defined.

@posva
Copy link
Member

posva commented Oct 21, 2019

See #2021
Good news are you can fully customize things with the slot api

@posva posva closed this as completed Oct 21, 2019
@jeff-hykin
Copy link
Author

jeff-hykin commented Oct 21, 2019

Hi @posva, the issue isn't about having the capability, its a feature request for a more straightforward API.

Thanks for the mention of the slots API though, thats probably the best current method so I'll add it as a 6th solution to the original post. I read about the slots API, but the documentation describes it as "advanced", "low-level customization", that was "primarily for library authors". I figured something like that wouldn't be required for something as simple as a making a button click go to a new page. If an advanced API is required, then I'd suggest it needs to be adjusted.

Others likely will not know that this is the recommended solution since the stack overflow post doesn't mention it, and the documentation doesn't describe this as one of the use-cases for the slots API.

I'll add this answer to the stack overflow post.

@posva
Copy link
Member

posva commented Oct 22, 2019

This does not behave the same as an href or router-link. For example, router-links can be opened in a new tab by pressing CMD/CTRL CLICK, however that behavior doesn't happen on an @click like the one above.

That's expected, the cmd/ctrl click is native, it's not emulated by Vue Router. Buttons do not have that behavior, and I don't recommend you to change it. If you want the button to behave like a link, it should be a link for usability reasons like accessibility. If you still want to use a button, you will have to emulate link behaviors, but that has nothing to deal with Vue Router

@vogla
Copy link

vogla commented Nov 10, 2021

If you want the button to behave like a link, it should be a link for usability reasons like accessibility.

There are browsers out there that treat anchor-tags and button-tags very differently. Your opinion that everyone should just quit using buttons or list-elements for hyperlinks is very naive. Please give us back the router-link "tag" attribute, that was a perfectly simple solution in vue2. The "v-slot" solution is absurdly complicated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@posva @vogla @jeff-hykin and others