im trying to use v-if to render 2 buttons in different containers on page, depending on screen size
is there way how to change parent of items in @media or way how to use screen size in v-if condition?
i tried
<div v-if="window.innerWidth < 860">
<!-- Some code -->
</div>
but it throws me "TypeError: Cannot read properties of undefined (reading ‘innerWidth’)"
(when i use just media query, there appears bug with radio btns, when they needs 2 clicks to get :checked styles)
when i tried @media, in fact there was 4 buttons, that binded to 2 variables
<!-- button code -->
<label>
<input type="radio" name="month-season" id="month" value="month" v-model="monthSeason">
<null-button>
<img src="../assets/green-smile.png" alt="#" id="month-icon">
text
</null-button>
</label>
<!-- null-button -->
<div class="parent">
<div class="container">
<slot></slot>
</div>
<div>
<!-- styles for button -->
<style>
.month-season {
text-align: right;
label {
.container {
color: rgba(45, 206, 137, 1);
background: white;
img {
margin: 0 4px 0 0;
}
}
input:checked + .parent .container {
background: rgba(45, 206, 137, 1);
color: white;
img {
filter: brightness(1000%);
}
}
input {
appearance: none;
}
}
}
</style>
Error message when I use window.innerWidth
2
Answers
Vue3 SFC Playground
All JS expression that you use in a template are executed in a so called template context. It contains all stuff declared in a component and does NOT contains JS globals like
window
and its props likealert
. So you should usewindow
outside a template or to add toapp.config.globalProperties
.But adding
window
to the context doesn’t solve you problem because JS expressions using it aren’t reactive and your code would work only on initial component rendering.So you should go reactive here. A common Vue3 approach would be using composables here.
We could use 2 different approaches here. Either using
matchMedia
orwindow.innerWidth
as you tried.With
matchMedia
you can go with any CSS media query you like.So in the both cases you listen for appropriate events and update
ref
that is used further in a template.If you listen on
window
don’t forget to remove the listener when the component is unmounted otherwise you will have problems of ghost event handlers.So your
matchMedia
composable:Your
window.innerWidth
composable:And the usage:
Maybe try using useWindowSize or useElementSize.