Breakpoints reactivity with Tailwind and VueJS

florent giraud - May 14 '19 - - Dev Community

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>

Enter fullscreen mode Exit fullscreen mode

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/

. . . . . . . . . . . . . . . . . . .