Hello VUEJS lovers ! ❤️
TL:TR
Before Tailwind I used Vuetify. Vuetify is an incredible css framework!
But 🤔
I faced some issues with Vuetify:
- "Forced" to use Vuetify components
- Making changes in some cases could become really difficult....
Since then, I've discovered Tailwind!
Tailwind is what we call a "Css utility" which allows us to have much more modularity.
With that being said.
What I liked and didn't find with Tailwind are the Breakpoints Reactivity connected to VueJS. It let you change css classes dynamically or styles etc...
<template>
<div :class="{classCustom: breakpoints.xs}" ></div>
</template>
So I decided to do it myself.
Let's go connect Tailwind breakpoints reactivity with VueJS 😇
First, I was inspired by what Vuetify was doing, as integrate the breakpoints logic via Plugins. It is handy since it adds some "globals property" => The Breakpoints.
Yeah but it's "global". I don't like this aspect of globals, that mean you have to take that and ok... If I don't want them inside my component and save amount of code after transpilation.
On top of that, the customisation of the properties name etc are almost impossible.
So I decided to take advantage of the Vue Observable.
import Vue from 'vue'
const screens = {
sm: 640,
md: 768,
lg: 1024,
xl: 1280
}
const sm = val => val >= screens.sm && val <= screens.md
const md = val => val >= screens.md && val <= screens.lg
const lg = val => val >= screens.lg && val <= screens.xl
const xl = val => val >= screens.xl
const getBreakpoint = w => {
if (sm(w)) return 'sm'
else if (md(w)) return 'md'
else if (lg(w)) return 'lg'
else if (xl(w)) return 'xl'
else return 'all'
}
const debounce = function(func, wait) {
var timeout
return () => {
const later = function() {
timeout = null
}
const callNow = !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) func()
}
}
const breakpoints = Vue.observable({
w: window.innerWidth,
h: window.innerHeight,
is: getBreakpoint(window.innerWidth)
})
window.addEventListener(
'resize',
debounce(() => {
breakpoints.w = window.innerWidth
breakpoints.h = window.innerHeight
breakpoints.is = getBreakpoint(window.innerWidth)
}, 200),
false
)
export default breakpoints
And you can now use them just simply like this...
<template>
<div>{{ breakpoints.is }} {{ breakpoints.w }} {{ breakpoints.h }} </div>
</template>
<script>
import breakpoints from '@/plugins/breakpoints'
export default {
name: 'Component',
data: () => {
return {
breakpoints
}
}
}
</script>
And That's it! Since we are using Vue.observable, vue will automatically put those data reactive.
ps: It work's well with functional components!
<script>
import breakpoints from '@/plugins/breakpoints.js'
export default {
name: 'TitleXL',
functional: true,
props: {
text: {
type: String,
default: ''
}
},
render: (h, { data, props }) => {
const textW = breakpoints.mdAndUp ? 'text-5xl' : 'text-3xl'
return (
<div class={textW} {...data}>
{props.text}
</div>
)
}
}
</script>
Now you don't get data where you don't need it to be anymore ❤️
As you know, any code can be improved. If you have any suggestion,
Feel free to contact me or let a comment or just like the article :)
my twitter: https://twitter.com/giraud_florent
my linkedin: https://www.linkedin.com/in/fgiraud42/
Top comments (5)
Thanks for this! I was fairly new to observables so this helped out!
I had one remark though: why the
x >= current && x < next
statements, when you can just start at the largest breakpoint and descend, skipping the upper bound check on the lower breakpoints.the result would be the same, but it's a lot shorter and a lot easier to wrap your head around.
Thank you very much, I used your code to create a composable function :
Slight refactor of your implemetation... to ensure the breakpoint gets calculated on load, if there is no resize.
Great utility. I've extended this to reference my breakpoints from the tailwind config so that they can be managed all in one place. My breakpoints are stored (as em's) in the tailwind config like so:
And my breakpoint utility imports and converts them to pixels so we can make use of them, just modify the
const screens
variable to use the imported values like so:glad it helps you :)