Skip to content
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

[feature request] new v-slot syntax does not support slot names that start with a square bracket [ or names with spaces #10390

Closed
tmorehouse opened this issue Aug 13, 2019 · 22 comments

Comments

@tmorehouse
Copy link

tmorehouse commented Aug 13, 2019

What problem does this feature solve?

We use slot names that use a bracketed syntax (specifically for dynamic slot names) i.e. slot="[foo][bar]").

v-slot: currently supports slots names with square brackets, as long as they are not the first character of the slot name. i.e. v-slot:foo[bar]="scope" (works), but not v-slot:[foo][bar]="scope" (does not work)

HTML5 allows for custom attributes with square brackets in the attribute name, as long as they do not start with restricted characters. However, in the case of v-slot, the attribute starts with v, so slot names that start with [ should work as expected (i.e. v-slot:[foo.bar] or v-slot:[foo][bar])

Using the deprecated slot="[foo]" syntax works as expected.

What does the proposed API look like?

v-slot adds support for slot names that start with a [, such as v-slot:[foo][bar]="scope"

There is no actual change to the API from the user perspective, just a change to the underlying code.

My guess that this is an issue with Vue template compiler:

From the template compiler on the Vuejs.org site (https://vuejs.org/v2/guide/render-function.html#Template-Compilation):

Does not work:

image

Does Work:

image

@tmorehouse tmorehouse changed the title New v-slot syntax does not support slot names that start with a square bracket [ [feature request]: new v-slot syntax does not support slot names that start with a square bracket [ Aug 13, 2019
@tmorehouse tmorehouse changed the title [feature request]: new v-slot syntax does not support slot names that start with a square bracket [ [feature request] new v-slot syntax does not support slot names that start with a square bracket [ Aug 13, 2019
@posva
Copy link
Member

posva commented Aug 13, 2019

Unfortunately, brackets are for dynamic slot names: https://vuejs.org/v2/guide/components-slots.html#Dynamic-Slot-Names

so you will have to use a different naming convention

@posva posva closed this as completed Aug 13, 2019
@jacekkarczmarczyk
Copy link

image

@tmorehouse
Copy link
Author

tmorehouse commented Aug 13, 2019

@posva will using a name such as v-slot:foo[bar]="scope" and v-slot:foo[bar][baz]="scope" be safe for future use? As the square brackets makes sense when referring to slots based on a multi-dimensional array of data (our component is dynamic when it comes to slot name, so the slot names will change based on user supplied data)

@sirlancelot
Copy link

I would've expected a bracketed string literal to work, but it appears the parser doesn't like that:

<component>
  <template v-slot:['[foo][bar]']>TEST</template>
</component>

Template Explorer Example

@jacekkarczmarczyk
Copy link

@sirlancelot it works with backticks though (see my example), maybe it should be documented?

@posva
Copy link
Member

posva commented Aug 14, 2019

quotes seems to be forbidden. Since they can be used to delimiter value in html attributes (data-attr="hey" or data-attr='hey') but that's not the case for the backticks. Or that's what I think the intention was and if that's the case, it should be documented at https://vuejs.org/v2/guide/components-slots.html#Dynamic-Slot-Names. But I don't know if we the recommendation would be to also avoid strings like [foo][bar]. Although that could also be changed in the regex
Keep in mind there is a PR at #9785 and that would be the regex that needs to be modified to accommodate new cases

Personally I wouldn't use a name for a slot if it cannot be used as a variable name. It also makes it easier to access them through $scopedSlots. I would use a delimiter to split the namespaces so they can be easily joinable. Something like $ or _: foo$bar. That way can be easily walkable with functions in nested objects. But at the same time, if a key doesn't create any problems to be parsed in html and can be used as the key of an object, it would make sense to support it

@tmorehouse
Copy link
Author

tmorehouse commented Aug 14, 2019

@posva For reference, here is our use case of the slot names which are determined at runtime:

https://bootstrap-vue.netlify.com/docs/components/table#custom-data-rendering

Note that we are using render functions internally to generate the table cells. Users provide a list of "fields" for their table, and we look to see if the user has provided a slot for that field to do custom rendering on the cell.

Note that each field name could contain dot (in the case the field's key points to a nested object value in the table row), underscores, letters, numbers (and in some cases spaces... anything that can be used as an object property key)

@Justineo
Copy link
Member

You should use scoped slots.

@tmorehouse
Copy link
Author

tmorehouse commented Aug 14, 2019

@Justineo we are using scoped slots (we are providing the scoped slots to consumers, and the consumers use these slots to place their custom formatting in).

The issue is that the slot names are defined by the consumer, following a particular naming convention. As the library provider, we do not know the full name of the scoped slot until runtime (when the user provides a list of fields for the table data). We then lookup in the $scopedSlots object to see if a scoped slot exists for a particular field, and if it does then we use that, other wise we just render the table's row's field data as is.

@Justineo
Copy link
Member

I see. But what would v-slot:[foo][bar] mean in your example?

@tmorehouse
Copy link
Author

tmorehouse commented Aug 14, 2019

It was just an example for using brackets in slot names. We were also thinking of, in the future, a way to target specific rows/columns (cells) based on the [x][y] axis. The older slot="name" syntax had a lot more flexibility when it comes to slot names, compared to v-slot:name syntax which is restrictive due to limitations of what is allowed in attribute names (as well as the loss of case sensitivity in slot names, specifically if a consumer is using in-document templates)

@sirlancelot
Copy link

sirlancelot commented Aug 14, 2019

As long as the slot name starts with a letter or number you should be fine. v-slot:cell[x][y] works as expected which is roughly equivalent to the Bootstrap table example above.

@tmorehouse
Copy link
Author

tmorehouse commented Aug 14, 2019

It is too bad the new slot/scope syntax wasn't split into two "directives":

<!-- pass a string literal as the slot name -->
<template v-slot="'slotName'" v-scope="{ some, props, here }"></template>

<!-- pass a variable containing the slot name -->
<template v-slot="someVar" v-scope="{ some, props, here }"></template>

As this would retain case sensitivity on slot names (when using browser templates), allow spaces in slot names, and get around the restrictions that attribute names have (case insensitivity, special chars, and spaces)

Within render functions, one can always use this.$scopedSlots[slotname](scope)

@tmorehouse
Copy link
Author

@posva see my comment at vuejs/rfcs#2 (comment) regarding the limitations of the new v-slot syntax and how it might be considered a step backwards in some situations, and re the deprecation of the old slot-syntax (which should be retained).

@posva
Copy link
Member

posva commented Aug 23, 2019

I saw it but nothing really changes... Things were already brought up. The problem you are highlighting is using weird names for slots which I would avoid in general and can be solved with render functions (in the library) which totally fits an advanced use case or using other characters as I said above so that end users are not limited. To recap:

  • no limitation in html because we can use strings
  • slot names can be adapted for libraries to make them valid in html
  • in-browser users will always have less things than webpack users

Also, having 2 attributes instead of one to accommodate a very specific and non-readable use case doesn't seem to be worth to me

@tmorehouse
Copy link
Author

tmorehouse commented Aug 23, 2019

@posva, I don't think you understand the situation I am referring to. Render functions don't fix the issues for users of the 3rd party library (it only fixes it for the 3rd party library portion).

A user of the 3rd party library using SFC templates will run into the issue, and users of x-templates will also run into issues (specifically with case sensitive names being lost in browser).

Example... user is using <b-table> from BootstrapVue, using a data items provider API (which they do not have control of), which returns records (an array of objects, on object per row of data). The object properties are keyed by a camelCase or PascalCase key (or keys with spaces... which is valid JavaJcript/JSON). In the <b-table> component,

The table will render fine (as we use render functions to generate the table). But users can provide scoped slots to provide custom formatting for each field key in the table data (i.e. a column). the scoped slot name is based on the row's object property names (keys). So the scoped slot names (which are dynamic based on the fields present in the data) are in the format of cell[<field key>], where <field key> is the object property name (key), which could be mixed upper/lower case, have spaces, etc. The ability for the user to use slot name cell[User ID] no longer works when using v-slot, where as it worked fine for slot="cell[User ID]". This is the issue.

It is more common situation than you are thinking it is, specifically when users have no control over the data being sent to them.

The docs should be more clear on the limitations for in-browser users. The slot documentation section has no mention of the upper/lowercase issues.

I'm not sure what you are referring to by "non-readable use case"

An example of this use case can be found at:
https://bootstrap-vue.netlify.com/docs/components/table#scoped-field-slots

@tmorehouse
Copy link
Author

tmorehouse commented Aug 23, 2019

no limitation in html because we can use strings

Not true. you can only use strings without spaces, and ones that do not have special characters used by directive attributes: i.e. . in a scoped slot name, as it will instruct Vue to treat it as a directive modifier, which is a very common use case for users of <b-table> i.e. when selecting a nested object key: v-slot:cell[name.first]="{ value, field, index }" and v-slot:cell[name.last]="{ value, field, index }" will not work because of the . in the attribute name.

This now requires consumers to have to re-map their data arrays and loose their original data structure

@posva
Copy link
Member

posva commented Aug 23, 2019

I totally agree for the docs, the limitations should be mentioned but keep in mind this is an advanced and very specific use case that do not affect users in general and only affects a few library authors. We will be very happy if you want to lead the discussion there with other people facing the same issue and see how to improve the docs.

Not true. you can only use strings without spaces

Talking about loader vs no-loader: spaces cannot work on html either as it's on the attribute side. The rest I already answered...

@tmorehouse
Copy link
Author

tmorehouse commented Aug 23, 2019

Spaces cannot work on html either

Not entirely true. true for attribute names, not not true for attribute values.

You can use strings with spaces as an attribute value: slot="foo bar", and one can use . in attribute values slot="foo.bar" without issue. not so with v-slot, which is why I consider the new v-slot (directive-ish) syntax a step backwards in flexibility.

... and only affects a few library authors

And many, many, more consumers of those libraries (you are forgetting about the consumers, which is really the people affected by the issue). It is not just BootstrapVue users, but includes consumers of libs like Vuetify (they are now also affected by this issue, and will be SOL when Vue 3.x rolls out) when it comes to slots names that are not known until rum-time.

@tmorehouse tmorehouse changed the title [feature request] new v-slot syntax does not support slot names that start with a square bracket [ [feature request] new v-slot syntax does not support slot names that start with a square bracket [ or have spaces Aug 23, 2019
@tmorehouse tmorehouse changed the title [feature request] new v-slot syntax does not support slot names that start with a square bracket [ or have spaces [feature request] new v-slot syntax does not support slot names that start with a square bracket [ or names with spaces Aug 23, 2019
@posva
Copy link
Member

posva commented Aug 23, 2019

And many, many, more consumers of those libraries (you are forgetting about the consumers, which is really the people affected by the issue).

I did think about end users. As I said I don't think a slot should be named something else or [this][other]. It would be much better to name it something-else or this-other. So maybe we should be stricter about slot names so library authors are enforced to use html-friendly slot names for static slot names

when it comes to slots names that are not known until rum-time

Those are usually stored in variables and used through v-slot:[slotName] and in those cases it doesn't matter if they have a [ or . If they are generated and still meant to be consumed by end users without some kind of automation (loops, etc) they can use a different syntax that is also valid as variable names and expose less problems like image__label

@tmorehouse
Copy link
Author

tmorehouse commented Aug 23, 2019

That is why I prefer passing slot names as an attribute value instead of the attribute name (inside the double quotes, as with the old slot="name" syntax). the only restriction in attribute values is strings containing ". Attribute values are never lowercased by the browser, support a wider range of characters, etc, and work with both SFC and in-browser templates equally. And the loss of that flexibility when the deprecated slot/slot-props is removed in v3.x is a big disappointment (now users need to pre-proccess data, library authors have to massage slot names when requesting the slot function, etc. much more overhead, and users have to massage slot names on their end as well.

@thedamon
Copy link

I'd like to add another situation that is impossible with the new slot syntax:

A component that you can pass any number of slots to and uses the names in content. We have a component like this for tabs:

<NTabs>
  <template slot="Tab 1 title">tab content</template
  <template slot="Tab 2 title">tab content</template
  <template slot="¥">tab content</template
</NTabs>

This was an intuitive way of dynamically passing any number of slots to a component without any unnecessary additional props (like making up an ID to be the slot name), and without needing an additional component.

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

6 participants