question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: New syntax for scoped slots

See original GitHub issue

This is an update of #9180 where we attempt to finalize a new syntax proposal for scoped slots (in a backwards compatible way).

Rationale

When we first introduced scoped slots, it was verbose because it required always using <template slot-scope>:

<foo>
  <template slot-scope="{ msg }">
    <div>{{ msg }}</div>
  </template>
</foo>

To make it less verbose, in 2.5 we introduced the ability to use slot-scope directly on the slot element:

<foo>
  <div slot-scope="{ msg }">
    {{ msg }}
  </div>
</foo>

This means it works on component as slot as well:

<foo>
  <bar slot-scope="{ msg }">
    {{ msg }}
  </bar>
</foo>

However, the above usage leads to a problem: the placement of slot-scope doesn’t always clearly reflect which component is actually providing the scope variable. Here slot-scope is placed on the <bar> component, but it’s actually defining a scope variable provided by the default slot of <foo>.

This gets worse as the nesting deepens:

<foo>
  <bar slot-scope="foo">
    <baz slot-scope="bar">
      <div slot-scope="baz">
        {{ foo }} {{ bar }} {{ baz }}
      </div>
    </baz>
  </bar>
</foo>

It’s not immediately clear which component is providing which variable in this template.

Someone suggested that we should allow using slot-scope on a component itself to denote its default slot’s scope:

<foo slot-scope="foo">
  {{ foo }}
</foo>

Unfortunately, this cannot work as it would lead to ambiguity with component nesting:

<parent>
  <foo slot-scope="foo"> <!-- provided by parent or by foo? -->
    {{ foo }}
  </foo>
</parent>

This is why I now believe allowing using slot-scope without a template was a mistake.

In 2.6, we are planning to introduce a new syntax for scoped slots.

Goals of the new proposal

  • Still provide succinct syntax for most common use cases of scoped slots (default slots)

  • Clearer connection between scoped variable and the component that is providing it.

Syntax Details

  • Introducing a new special attribute: slot-props.

    • It can be used on a component to indicate that the component’s default slot is a scoped slot, and that props passed to this slot will be available as the variable declared in its attribute value:

      <foo slot-props="{ msg }">
        {{ msg }}
      </foo>
      
    • It can also be used on <template> slot containers (exactly the same usage as slot-scope in this case):

      <foo>
        <template slot="header" slot-props="{ msg }">
          {{ msg }}
        </template>
      </foo>
      
    • It can NOT be used on normal elements.

  • slot-props also has a shorthand syntax: ().

    The above examples using shorthand syntax:

    <foo ()="{ msg }">
      {{ msg }}
    </foo>
    
    <foo>
      <template slot="header" ()="{ msg }">
        {{ msg }}
      </template>
    </foo>
    

    The shorthand is () because it resembles the starting parens of an arrow function and loosely relates to “creating a scope”. An arrow function is also typically used for render props, the equivalent of scoped slots in JSX.

Comparison: New vs. Old

Let’s review whether this proposal achieves our goals outlined above:

  • Still provide succinct syntax for most common use cases of scoped slots (single default slot):

    Can we get any more succinct than this?

    <foo ()="{ msg }">{{ msg }}</foo>
    
  • Clearer connection between scoped variable and the component that is providing it:

    Let’s take another look at the deep-nesting example using current syntax (slot-scope) - notice how slot scope variables provided by <foo> is declared on <bar>, and the variable provided by <bar> is declared on <baz>

    <foo>
      <bar slot-scope="foo">
        <baz slot-scope="bar">
          <div slot-scope="baz">
            {{ foo }} {{ bar }} {{ baz }}
          </div>
        </baz>
      </bar>
    </foo>
    

    This is the equivalent using the new syntax:

    <foo ()="foo">
      <bar ()="bar">
        <baz ()="baz">
          {{ foo }} {{ bar }} {{ baz }}
        </baz>
      </bar>
    </foo>
    

    Notice that the scope variable provided by a component is also declared on that component itself. The new syntax shows a clearer connection between slot variable declaration and the component providing the variable.

Here are some more usage examples using both the new and old syntax.

Q&A

Why a new attribute instead of fixing slot-scope?

If we can go back in time, I would probably change the semantics of slot-scope - but:

  1. That would be a breaking change now, and that means we will never be able to ship it in 2.x.

  2. Even if we change in in 3.x, changing the semantics of existing syntax can cause a LOT of confusion for future learners that Google into outdated learning materials. We definitely want to avoid that. So, we have to introduce a new attribute to differentiate from slot-scope.

What happens to slot-scope?

It’s going to be soft-deprecated: it will be marked deprecated in the docs, and we would encourage everyone to use / switch to the new syntax, but we won’t bug you with deprecation messages just yet because we know it’s not a top priority for everyone to always migrate to the newest stuff.

In 3.0 we do plan to eventually remove slot-scope, and only support slot-props and its shorthand. We will start emitting deprecation messages for slot-scope usage in the next 2.x minor release to ease the migration to 3.0.

Since this is a pretty well defined syntax change, we can potentially provide a migration tool that can automatically convert your templates to the new syntax.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:17
  • Comments:15 (7 by maintainers)

github_iconTop GitHub Comments

5reactions
dimensicommented, Jan 12, 2019

@yyx990803 () ={} looks looks weird. It looks just as disgusting as render props in jsx. And looks like not from vue.

<AppWrapper class="wrapper"
     prop-one="one"
     prop-two="two"
     ()="{ wrap }">
      <AppTranslate t="hello" ()="{ text }">
        <AppButton @click="wrap.handler">{{ text }}</AppButton>
      </AppTranslate>
</AppWrapper>

the more components there are, the easier it will be in the markup to lose this shorthands.

4reactions
4refaelcommented, Jan 14, 2019

If I may suggest a different shorthand

<foo &="{ msg }">
  {{ msg }}
</foo>

The ampersand is known in programming as a reference/pointer to variables.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Slots - Vue.js
In 2.6.0, we introduced a new unified syntax (the v-slot directive) for named and scoped slots. It replaces the slot and slot-scope attributes, ......
Read more >
Vue named and scoped slots - new syntax in 2.6 - swiecaJS
Vue 2.6 gave us new syntax for scoped slots. The v-slot directive. ... Let's start with regular slots They can be as a...
Read more >
Vue.js 2.6: New syntax for scoped slots released - HelpDev
The new syntax combines normal and scoped slots under v-slots , as Evan ... Through the RFC, the new syntax for slots, which...
Read more >
How to use the new v-slot directive in Vue.js - VueDose
In order to understand how it does simplify the syntax, let's see how's it in current scoped slots. Imagine you have a List...
Read more >
Vue 2.6 is now out with a new unified syntax for slots, and more
This update is fully backward compatible. According to the RFC, slot-scope will be soft-deprecated. This means that it will be marked deprecated ...
Read more >

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found