Search code examples
vue.jsvuejs2vuetify.js

Meaning of v-slot:activator="{ on }"


Looking at the Vuetify example code for v-toolbar, what is the purpose of v-slot:activator="{ on }"? For example:

<template v-slot:activator="{ on }">
  <v-toolbar-title v-on="on">
    <span>All</span>
    <v-icon dark>arrow_drop_down</v-icon>
  </v-toolbar-title>
</template>

<script>
  export default {
    data: () => ({
      items: [
        'All', 'Family', 'Friends', 'Coworkers'
      ]
    })
  }
</script>

As far as I can see, on is not a defined variable anywhere, so I don't see how this is working. When I try it in my project, Internet Explorer throws an error on the <template v-slot:activator="{ on }">, but if I remove it, the page renders.


Solution

  • You're likely referring to this example:

    <v-toolbar color="grey darken-1" dark>
      <v-menu :nudge-width="100">
        <template v-slot:activator="{ on }">
          <v-toolbar-title v-on="on">
            <span>All</span>
            <v-icon dark>arrow_drop_down</v-icon>
          </v-toolbar-title>
        </template>
    
        ...
      </v-menu>
    </v-toolbar>
    

    The following line declares a scoped slot named activator, and it is provided a scope object (from VMenu), which contains a property named on:

    <template v-slot:activator="{ on }">
    

    This uses destructuring syntax on the scope object, which IE does not support.

    For IE, you'd have to dereference on from the scope object itself:

    <template v-slot:activator="scope">
      <v-toolbar-title v-on="scope.on">
    

    But the ideal solution IMO is to use a Vue CLI generated project, which includes a Babel preset (@vue/babel-preset-app) to automatically include the transforms/polyfills needed for the target browsers. In this case, babel-plugin-transform-es2015-destructuring would be automatically applied during the build.

    Details on the activator slot

    VMenu allows users to specify a slotted template named activator, containing component(s) that activate/open the menu upon certain events (e.g., click). VMenu provides listeners for those events via an object, passed to the activator slot:

    <v-menu>
      <template v-slot:activator="scopeDataFromVMenu">
        <!-- slot content goes here -->
      </template>
    </v-menu>
    

    The slot content can access VMenu's event listeners like this:

    <v-menu>
      <template v-slot:activator="scopeDataFromVMenu">
        <button v-on="scopeDataFromVMenu.on">Click</button>
      </template>
    </v-menu>
    

    For improved readability, the scoped data can also be destructured in the template:

    <!-- equivalent to above -->
    <v-menu>
      <template v-slot:activator="{ on }">
        <button v-on="on">Click</button>
      </template>
    </v-menu>
    

    The listeners from the scope object are passed to the <button> with v-on's object syntax, which binds one or more event/listener pairs to the element. For this value of on:

    {
      click: activatorClickHandler // activatorClickHandler is an internal VMenu mixin
    }
    

    ...the button's click handler is bound to a VMenu method.