How to Easily Create Versatile Menus in Vuetify

A menu is a versatile component in a user interface. It shows a popover that can serve various functions, such as displaying a list of options. They can be used with other components like a toolbar, app bar, or a button. In this article, we’re to learn how to create and customize a menu in Vuetify.

The v-menu Component

Vuetify provides the v-menu component for creating a menu. We use the activator slot to set the component that will activate the menu when clicked. We set it to a button in this example:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>

Clicking the button will display the popover menu:

Creating a menu in Vuetify.

Creating an Absolute Menu in Vuetify

We can place a menu on the top of the element in the activator slot with the absolute prop.

<template>
  <v-app>
    <div class="d-flex justify-center ma-4">
      <v-menu offset-y absolute>
        <template v-slot:activator="{ on, attrs }">
          <v-card
            class="portrait"
            img="https://picsum.photos/1920/1080?random"
            height="300"
            width="600"
            v-bind="attrs"
            v-on="on"
          ></v-card>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Creating an an absolute menu in Vuetify.

Absolute Menu without Activator

We can also use a menu without an activator by using absolute together with the position-x and position-y props. This is useful for creating a context menu:

<template>
  <v-app>
    <div>
      <div class="d-flex justify-center ma-4">
        <v-card
          :ripple="false"
          class="portrait"
          img="https://picsum.photos/1920/1080?random"
          height="300"
          width="600"
          @contextmenu="show"
        ></v-card>
      </div>
      <v-menu
        v-model="showMenu"
        :position-x="x"
        :position-y="y"
        absolute
        offset-y
      >
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Option {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
  data: () => ({
    showMenu: false,
    x: 0,
    y: 0,
  }),

  methods: {
    show(e) {
      e.preventDefault();
      this.showMenu = false;
      this.x = e.clientX;
      this.y = e.clientY;
      this.$nextTick(() => {
        this.showMenu = true;
      });
    },
  },
};
</script>
Displaying a menu without an activator.

Closing the Menu on Click

The close-on-click prop determines whether the menu closes when it loses focus or not.

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y :close-on-click="true">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>

Here close-on-click is set to true, so clicking on another element will close the menu:

Setting the close-on-click prop to true

If we set it to false:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y :close-on-click="false">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>

It will remain open even when we click on another element or remove its focus:

Setting the close-on-click prop to false.

Close Menu on Content Click

We can use the close-on-content-click prop to determine whether the menu should be closed when its content is clicked.

Setting close-on-content-click to true:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y :close-on-content-click="true">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="purple accent-4" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting close-on-content-click to true on a menu.

Setting close-on-content-click to false:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y :close-on-content-click="false">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="purple accent-4" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting close-on-content-click to false on a menu.

Disabled Menu

We can prevent a menu from being opened with the disabled prop:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y disabled>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="green" dark v-bind="attrs" v-on="on"> Dropdown </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
A disabled menu.

Offset X

We can use the offset-x prop to offset the menu by the X-axis to make the activator visible.

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-x>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Using the offset-x prop on a menu.

Offset Y

We can also offset the menu by the Y-axis to make the activator visible.

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting offset-y on a menu.

Offset X and Offset Y

We can also combine these two props:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-x offset-y>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Combining the v-menu offset-x and offset-y props.

Open Menu on Hover

Setting the open-on-hover prop to true will make the menu open when its activator is hovered over.

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu open-on-hover offset-y>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="teal" dark v-bind="attrs" v-on="on"> Dropdown </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Making a menu open on hover in Vuetify.

Creating a Rounded Menu in Vuetify

The rounded prop allows us to customize the border-radius of a menu.

Setting it to 0 will remove the border-radius:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y rounded="0">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="blue" dark v-bind="attrs" v-on="on">
            Removed Radius
          </v-btn>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Removing the menu radius with Vuetify.

We can give the menu a large border-radius by setting rounded to true:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y rounded="lg">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="indigo" dark v-bind="attrs" v-on="on">
            Large Radius</v-btn
          >
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting a large menu border radius with Vuetify.

We can also specify a custom border-radius, for example:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu offset-y rounded="b-xl">
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="red" dark v-bind="attrs" v-on="on">
            Custom Radius</v-btn
          >
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting a custom menu border radius with Vuetify.

Using a Menu with a Tooltip

We can also display a tooltip for a menu. We do this by nesting activator slots with the v-slot syntax and attaching the props of the slots to the same activator component (a button in this case).

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu>
        <template v-slot:activator="{ on: menu, attrs }">
          <v-tooltip bottom>
            <template v-slot:activator="{ on: tooltip }">
              <v-btn
                color="primary"
                dark
                v-bind="attrs"
                v-on="{ ...tooltip, ...menu }"
              >
                Dropdown w/ Tooltip</v-btn
              >
            </template>
            <span>This is a tooltip</span>
          </v-tooltip>
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Using a dropdown with a tooltip.

Custom Menu Transitions in Vuetify

We can also customize the transition that the menu will use to open and close. Vuetify comes with three standard transitions: scale, slide-x and slide-y.

Scale Transition

The scale-transition makes the menu grow in size when opening, and shrink back when closing:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu transition="scale-transition" origin="center center" bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Scale Transition</v-btn
          >
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting the menu transition to scale-transition.

Slide X Transition

The slide-x-transition makes the menu slide in from the left when opening, and slide back out when closing:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu transition="slide-x-transition" bottom right>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Slide X Transition</v-btn
          >
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting the menu transition to slide-x-transition.

Slide Y Transition

The slide-y-transition makes the menu slide in from the top when opening, and slide back out when closing:

<template>
  <v-app>
    <div class="text-center ma-4">
      <v-menu transition="slide-y-transition" bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn color="primary" dark v-bind="attrs" v-on="on">
            Slide X Transition</v-btn
          >
        </template>
        <v-list>
          <v-list-item v-for="index in 4" :key="index">
            <v-list-item-title>Item {{ index }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting the menu transition to slide-y-transition.

Using a Menu with an App Bar

We can use a menu with a toolbar or app bar:

<template>
  <v-app>
    <v-app-bar app color="deep-purple accent-4" dark>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon> <v-icon> mdi-heart </v-icon> </v-btn>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>

        <v-list>
          <v-list-item v-for="n in 4" :key="n" @click="() => {}">
            Option {{ n }}
          </v-list-item>
        </v-list>
      </v-menu>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Using a menu with an app bar.

Conclusion

A menu is a versatile user interface component in a user interface that shows a popover that we can use for a variety of purposes. It can work with a button, a toolbar or an app bar. Vuetify provides the v-menu component for creating and customizing menus.



11 Amazing New JavaScript Features in ES13

This guide will bring you up to speed with all the latest features added in ECMAScript 13. These powerful new features will modernize your JavaScript with shorter and more expressive code.

11 Amazing New JavaScript Features in ES13

Sign up and receive a free copy immediately.

Leave a Comment

Your email address will not be published. Required fields are marked *