Skip to content

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

@jeff-hykin

Description

@jeff-hykin

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions