vue-breakpoint

A set of layout components for Vue.js

Usage no npm install needed!

<script type="module">
  import vueBreakpoint from 'https://cdn.skypack.dev/vue-breakpoint';
</script>

README

Vue-Breakpoint

npm npm downloads GitHub issues GitHub stars Conventional Commits

A vue layout component to provide dynamic, reactive media query information. Uses the match media api.

Heavily inspired from Full Stack Radio episode #81 and the vue-mq library.

Install

npm i vue-breakpoint

Currently two bundles are provided:

  • a basic global variable export for quick use in the browser
    • vue-breakpoint/dist/index.js exposes window.VueBreakpoint
  • an ES2015 module for use with any build system
    • vue-breakpoint/dist/index.esm.js

These are appropriately marked in the package.json manifest under main and module respectively. TypeScript typings are also provided via the types entry.

Exports

The package exports two items: a component and a plugin (BreakpointComponent, BreakpointPlugin). These two offer distinct use cases.

BreakpointPlugin

BreakpointPlugin registers the component <breakpoint /> globally, but uses a single media query manager internally. This makes extensive usage throughout your app efficient.

To install the plugin, provide an optional media query map. A default is provided that queries screen width according to the Bootstrap 4 breakpoints and aliases (xs, sm, md, lg, xl), but here's an example:

// ES Module
import { BreakpointPlugin } from "vue-breakpoint";
// Window global
const { BreakpointPlugin } = window.VueBreakpoint;

Vue.use(BreakpointPlugin, {
  print: { print: true },
  portrait: { orientation: "portrait" },
  mobile: { maxWidth: "600px" },
  mobilePortrait: { maxWidth: "600px", orientation: "portrait" },
  tablet: { minWidth: "601px", maxWidth: "800px" },
  desktop: { minWidth: "801px" },
});

For a better look at the possibilities of the media queries, have a look at the query builder's test suite. Also check out CSS Tricks for media queries.

BreakpointComponent

BreakpointComponent is a Vue component that accepts the breakpoint/media-query map as a prop. This means that each component instance manages it's own media queries, and can have isolated control to provide one-off responsive queries. It also means that if the breakpoint map gets updated, the component will remove all the old listeners and re-register it's media queries. This allows for dynamically responsive layouts—dynamic to whatever you want!

To use the discrete component, add it to your consuming component's components object.

// ES Module
import { BreakpointComponent } from "vue-breakpoint";
// Window global
const { BreakpointComponent } = window.VueBreakpoint;

const MyParentComponent = Vue.extend({
  components: {
    "my-breakpoint": BreakpointComponent,
  },
});

Usage

Start off by determining your own set of media queries/breakpoints, or use the built-in bootstrap 4 style map. You can find it's definition here in the source.

Once you have the breakpoints decided and the installation taken care of, wrap some of your layout in a <breakpoint> component (wrap an element/component with a single root node) and define the slot-scope attribute. The value of slot-scope is the parameter name for the object that will hold all the breakpoint values. For example:

<breakpoint>
  <!-- `media` now holds our breakpoint values -->
  <main slot-scope="media">
    <h1>Hello world!</h1>
    <!-- The breakpoint values are booleans -->
    <!-- for whether or not their condition is met. -->
    <!-- Remember, these are based on the query map keys provided. -->
    <p v-if="media.lgUp">I'm on a large screen!</p>
    <p v-if="media.mdOnly">I'm in-between...</p>
    <p v-if="media.smDown">I'm on a small screen!</p>
  </main>
</breakpoint>

Since the slot-scope is an object, it can also be destructured to pull out the relevant values more easily.

<breakpoint>
  <main slot-scope="{ smDown, mdUp, lgUp }">
    <my-navbar v-if="mdUp" />
    <my-mobile-navbar v-if="smDown" />
    <section :class="['content', {'font-size-mobile': smDown}">
      <h1>Hello world!</h1>
      <p v-if="lgUp">I'm on a large screen!</p>
      <p v-if="smDown">I'm on a small screen!</p>
    </section>
  </main>
</breakpoint>

When you need custom, one-off breakpoint logic, use the discrete component.

<!-- Main grid setup -->
<breakpoint>
  <main slot-scope="media">
    <my-navbar v-if="media.mdUp" />
    <my-mobile-navbar v-if="media.smDown" />
    <router-view />
    <!-- Unique media queries -->
    <custom-breakpoint breakpoint-map="breakpointMap">
      <p slot-scope="{ mobileLandscape }" v-if="mobileLandscape">
        For best viewing, we recommend portrait orientation.
      </p>
    </custom-breakpoint>
  </main>
</breakpoint>

<script>
/* Register the component and setup the query map. */
new Vue({
  components: {
    "custom-breakpoint": VueBreakpoint.BreakpointComponent
  },
  data: {
    breakpointMap: {
      mobileLandscape: { screen: true, orientation: 'landscape' }
    }
  }
})
</script>

For more info, consult the Vue documentation on scoped slots.

Try It Out

Hack on this fiddle: vue-breakpoint jsfiddle