Inertia: Add link "as" option

Created on 19 Oct 2020  路  3Comments  路  Source: inertiajs/inertia

Right now Inertia links are always rendered as anchor <a> elements. However, there are situations where it might make more sense to render a different element. I'm considering adding a new as attribute to support this behaviour.

<inertia-link href="/example" as="div">Example</inertia-link>

<!-- Renders as: -->
<div>Example</div>

Practical example

Consider a non-GET link, such as a logout link. If you were to try and open this link in a new tab/window, you would get a 405 (Method Not Allowed) error. And that's because by opening it in a new tab/window, it gets handled like a regular GET request.

<inertia-link href="/logout" method="post">Logout</inertia-link>

From an accessibility perspective, it would be better to use a button in these cases, since you can't open a button in a new tab/window.

<inertia-link href="/logout" method="post" as="button" type="button">Logout</inertia-link>

<!-- Renders as a button (an a click event listener) -->
<button type="button">Logout</button>

Deprecate non-GET anchor links

Considering the accessibility issues that come with using anchor links for non-GET requests, I wonder if it would be wise to actually deprecate this behaviour. We could do this by showing a console warning if the method is set to something other than get, and the element is an anchor link.

if (props.method !== 'get' && props.as === 'a') {
  console.warn('Creating post/put/patch/delete anchor links is discouraged as it causes "open in new tab/window" accessibility issues. Please specify a different element using the "as" option.')
}

Directives

An alternative approach is encouraging the use of directives instead. An inertia directive already exists in the Svelte adapter, and one has been started for the Vue adapter (#207). However, are directives even a thing in React?

Accessibility

It's worth noting that this feature has been intentionally avoided in React Router:

There have been multiple requests for it, but it just isn't something that the React Router team wants to encourage because using a non-anchor component for links begs for accessibility issues.

Ironically, the reason I want this feature is to fix accessibility issues caused by non-GET Inertia links.

core enhancement todo

Most helpful comment

Another idea would be to support slots / render functions. This is more verbose but does provide more flexibility. I think as is a good addition either way, just wanna share this because it solves similar problems.

Vue example:

<inertia-link href="/logout" method="POST" v-slot="{ visit }">
    <button @click="visit">Log out<button>
</inertia-link>

React example:

<InertiaLink href="/logout" method="POST">
    {({ visit }) => <button onClick="visit">Log out</button>}
</InertiaLink>

Also note that the current implementation of shouldIntercept is based on the a tag. I assume shift-clicking, etc. does need to be intercepted on a button, since shift-clicking a native button doesn't do anything.

All 3 comments

What about tag instead of as to be consistent with the Vue Router? (https://router.vuejs.org/api/#tag)

@hivokas If you look up, you'll notice that I actually had tag at first, but change it to as. I changed it because:

  1. In the React community, this is apparently always done using as.
  2. If someone wants to use a custom component (as="MyComponent"), then tag doesn't really make sense.

I actually had a chat with @adamwathan about this, because I know they had to make this decision on Headless UI, and those were the two reasons they decided to go with as.

Another idea would be to support slots / render functions. This is more verbose but does provide more flexibility. I think as is a good addition either way, just wanna share this because it solves similar problems.

Vue example:

<inertia-link href="/logout" method="POST" v-slot="{ visit }">
    <button @click="visit">Log out<button>
</inertia-link>

React example:

<InertiaLink href="/logout" method="POST">
    {({ visit }) => <button onClick="visit">Log out</button>}
</InertiaLink>

Also note that the current implementation of shouldIntercept is based on the a tag. I assume shift-clicking, etc. does need to be intercepted on a button, since shift-clicking a native button doesn't do anything.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mpskovvang picture mpskovvang  路  5Comments

JoeCianflone picture JoeCianflone  路  4Comments

philippkuehn picture philippkuehn  路  3Comments

MichaelDeBoey picture MichaelDeBoey  路  4Comments

kufdaw picture kufdaw  路  6Comments