You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: active-rfcs/0021-router-link-scoped-slot.md
+70-27Lines changed: 70 additions & 27 deletions
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,7 @@
9
9
- Remove `event` prop
10
10
- Stop automatically assigning click events to inner anchors
11
11
- Add a scoped-slot API
12
+
- Add a `custom` prop to fully customize `router-link`'s rendering
12
13
13
14
# Basic example
14
15
@@ -55,34 +56,12 @@ This implementation would:
55
56
- no longer accepts `event` -> use the scoped slot instead
56
57
- no longer works as a wrapper automatically looking for the first `a` inside -> use the scoped slot instead
57
58
58
-
## Custom `tag` prop
59
-
60
-
I am not sure about keeping the `tag` prop if it can be replaced which a scoped slot because it wouldn't handle custom components and except for very simple cases, we will likely use custom UI components instead of the basics ones:
(see below for explanation about the attributes passed to the scoped-slot)
79
-
80
59
## Scoped slot
81
60
82
-
A scoped slot would get access to every bit of information needed to provide a custom integration and allows applying the active classes, click listener, links, etc at any level. This would allow a better integration with frameworks like Bootstrap (https://getbootstrap.com/docs/4.3/components/navbar/). The idea would be to create a Vue component to avoid the boilerplate like bootstrap-vue does (https://bootstrap-vue.js.org/docs/components/navbar/#navbar)
61
+
A scoped slot would get access to every bit of information needed to provide a custom integration and allows applying the active classes, click listener, links, etc at any level. This would allow a better integration with UI frameworks like Bootstrap (https://getbootstrap.com/docs/4.3/components/navbar/). The idea would be to create a Vue component to avoid the boilerplate like bootstrap-vue does (https://bootstrap-vue.js.org/docs/components/navbar/#navbar)
@@ -91,6 +70,30 @@ A scoped slot would get access to every bit of information needed to provide a c
91
70
</router-link>
92
71
```
93
72
73
+
The `custom` prop is necessary to take full control over `router-link`'s rendering: not rendering a wrapping `a` element.
74
+
75
+
**Why is a `custom` prop necessary**: in Vue 3, scoped slots and regular slots cannot be differentiated from each other, which means vue router is unable to make the difference between these 3 cases:
In all three cases we need to render the slot content but `router-link` needs to know if it has to render a wrapping `a` element. In Vue 2, we are able to do so by checking `$scopedSlots` but in Vue 3, only `slots` exists. This means that the behavior is slightly different in Vue Router v3 and Vue Router v4:
84
+
85
+
- In v3, the `custom` prop is required (see [Adoption strategy](#adoption-strategy)) alongside `v-slot`. `router-link` will not wrap the slot content with an `a` element.
86
+
- In v4, the `custom` prop is **not** required alongside `v-slot`. It controls whether `router-link` should wrap its slot content with an `a` element or not:
The slot should provide values that are computed inside `router-link`:
@@ -101,6 +104,28 @@ The slot should provide values that are computed inside `router-link`:
101
104
-`isActive`: true whenever `router-link-active` is applied. Can be modified by `exact` prop
102
105
-`isExactActive`: true whenever `router-link-exact-active` is aplied. Can be modified by `exact` prop.
103
106
107
+
## The removal of the `tag` prop
108
+
109
+
The `tag` prop can be replaced which a scoped slot and make the code clearer while not being exposed to any caveat. Its removal will also lighten the vue-router library.
(see above for explanation about the attributes passed to the scoped-slot)
128
+
104
129
# Drawbacks
105
130
106
131
- Whereas it's possible to keep existing behaviour working and only expose a new behaviour with scoped slots, it will still prevent us from fixing existing issues with current implementation. That's why there are some breaking changes, to make things more consistent.
@@ -109,10 +134,28 @@ The slot should provide values that are computed inside `router-link`:
109
134
# Alternatives
110
135
111
136
- Keeping `event` prop for convienience
137
+
- Use a different named slot instead of a `prop`:
138
+
139
+
```vue
140
+
<router-link #custom="{ href }">
141
+
<a :href="href"></a>
142
+
</router-link>
143
+
144
+
<router-link v-slot:custom="{ href }">
145
+
<a :href="href"></a>
146
+
</router-link>
147
+
148
+
<router-link custom v-slot="{ href }">
149
+
<a :href="href"></a>
150
+
</router-link>
151
+
```
152
+
153
+
The adoption strategy in this case would be similar but the warning would tell the user to use a different slot instead of a prop named `custom`
154
+
155
+
- Create a new component like `router-link-custom` to differentiate the behavior. This solution is however heavier (in terms of size) than a prop or a different named slot. It is also less suitable than a prop because we are only changing a behavior of the component. The difference between the two components woud be too small to justify a whole new component.
112
156
113
157
# Adoption strategy
114
158
115
159
- Document new slot behaviour based on examples
116
-
- Deprecate `tag` and `event` with a message and link to documentation the remove in v4
117
-
118
-
# Unresolved questions
160
+
- Deprecate `tag` and `event` with a message in v3 and link to documentation, then remove in v4
161
+
- In v3, if no `custom` prop is provided when using a scoped slot, warn the user to use the `custom` prop
0 commit comments