'Vue js Vuetify custom component not rendered based on the display breakpoint
I have a custom component that basically is a v-btn component with specific style. When I'm using it inside v-menu activator with conditional based on display breakpoint, the custom component does not display on the screen. But if I use regular v-btn the button displays properly based on the display breakpoint. What am I doing wrong here?
https://codepen.io/jgunawan-dc/pen/XWzJqRy?editors=1010
<div id="app">
<v-app id="inspire">
<div class="text-center">
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<global-custom-button
v-if="$vuetify.breakpoint.mdAndDown"
v-bind="attrs"
v-on="on"
>
Show on medium and lower
</global-custom-button>
<v-btn v-else
color="primary"
dark
v-bind="attrs"
v-on="on"
>
Dropdown
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</v-app>
</div>
Vue.component('global-custom-button', {
template: '<v-btn outlined color="info" @click="$emit(\'click\', $event)"><slot></slot></v-btn>'
});
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
}),
})
Solution 1:[1]
For a quick fix, use v-show as @Rotiken said.
As another solution you could also register two global components and show/hide it using extra condition prop:
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<global-custom-button
:condition="$vuetify.breakpoint.mdAndDown"
v-bind="attrs"
v-on="on"
>
Show on medium and lower
</global-custom-button>
<global-custom-button-2
:condition="!$vuetify.breakpoint.mdAndDown"
v-bind="attrs"
v-on="on"
>
Dropdown
</global-custom-button-2>
</template>
...
</v-menu>
...
Vue.component('global-custom-button', {
template: '<v-btn v-if="condition" outlined color="info" @click="$emit(\'click\', $event)"><slot></slot></v-btn>',
props: ['condition']
});
Vue.component('global-custom-button-2', {
template: '<v-btn v-if="condition" color="primary" dark @click="$emit(\'click\', $event)"><slot></slot></v-btn>',
props: ['condition']
});
...
According to this CodePen, this also works.
Why this happens and why v-show works fine with same template: I can't give an exact answer, but there are some assumptions.
Vue.js docs says that v-if removes objects from DOM, whereas v-show changes its display state in CSS, but keep it in DOM.
Since you are using v-if in a vuetify v-menu component, perhaps the component has some methods for updating the v-slot:activator content that can conflict (and not performed at the same time) with conditional rendering using v-if and vuetify display breakpoints.
If you are familiar with TypeScript, you can look into v-menu sources or into activatable mixin sources. Maybe here you will find the true reason for this behavior.
If you just want to avoid such problems, use v-show in such cases.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alexander Shkirkov |
