Categories
Top Vue Packages

Top Vue Packages for Lazy Loading Image, Handling Keyboard Shortcut and More

ue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how the best packages for lazy loading images, handling keyboard shortcuts, adding a code editor, and adding numeric inputs.

v-lazy-image

We can add the v-lazy-image package to add lazy loading capability for images to our app.

To use it, we can run:

npm i v-lazy-image

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import { VLazyImagePlugin } from "v-lazy-image";

Vue.use(VLazyImagePlugin);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <v-lazy-image src="http://placekitten.com/500/500"/>
</template>

<script>
export default {};
</script>

We just add the v-lazy-image component.

Also, we can add a fallback image and a blurring effect for the images when it’s loading:

<template>
  <v-lazy-image
    src="http://placekitten.com/500/500"
    src-placeholder="http://placekitten.com/200/200"
  />
</template>

<script>
export default {};
</script>

 <style scoped>
.v-lazy-image {
  filter: blur(20px);
  transition: filter 0.7s;
}
.v-lazy-image-loaded {
  filter: blur(0);
}
</style>

We style the v-lazy-image and v-lazy-image-loaded to get the blurring effect when it’s loading.

It also emits the intersect and load events.

srcset lets us add multiple images with different sizes to load them according to different sizes.

vue-shortkey

vue-shortkey lets us add keyboard shortcut handling to our Vue app.

We can install it by running:

npm i vue-shortkey

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
Vue.use(require("vue-shortkey"));

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <button v-shortkey="['ctrl', 'alt', 'o']" @shortkey="theAction">button</button>
  </div>
</template>

<script>
export default {
  methods: {
    theAction(event) {
      alert("hello");
    }
  }
};
</script>

We registered the plugin and then add the v-shortkey directive to a button.

The array has the keys we want in the key combination.

shortkey event is emitted when the key combo is pressed.

Then theAction is run.

We can also handle multiple key combos in one handler.

To do that, we write:

<template>
  <div>
    <button v-shortkey="{up: ['arrowup'], down: ['arrowdown']}" @shortkey="theAction">button</button>
  </div>
</template>

<script>
export default {
  methods: {
    theAction(event) {
      switch (event.srcKey) {
        case "up":
          alert("up");
          break;
        case "down":
          alert("down");
          break;
        default:
          alert("default");
          break;
      }
    }
  }
};
</script>

We pass in an object to the directive.

Then we check in the theAction method to check the key pressed.

vue-prism-editor

The vue-prism-editor lets us add a simple code editor with syntax highlighting and line numbers.

To install it, we can run:

npm i vue-prism-editor prismjs

Then we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import "prismjs";
import "prismjs/themes/prism.css";
import VuePrismEditor from "vue-prism-editor";
import "vue-prism-editor/dist/VuePrismEditor.css"; // import the styles
Vue.component("prism-editor", VuePrismEditor);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <prism-editor v-model="code" language="js"></prism-editor>
    <pre>{{code}}</pre>
  </div>
</template>

<script>
import PrismEditor from "vue-prism-editor";
export default {
  components: {
    PrismEditor
  },
  data() {
    return {
      code: ""
    };
  }
};
</script>

to add the prism-editor to our app.

We set the language to js to highlight JavaScript.

v-model binds the entered code to the code state.

It supports many features like undo or redo, copy and paste, preserving indentation and more.

It emits change, keydown, keyup, and editor-click events.

We can add line numbers with the lineNumbers prop.

We can also disable the editor or make it read-only.

rackbeat-vue-numeric

rackbeat-vue-numeric lets us add a numeric input to our app.

To install it, we run:

npm i rackbeat-vue-numeric

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueNumeric from "vue-numeric";

Vue.use(VueNumeric);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <vue-numeric currency="$" separator="," v-model="price"></vue-numeric>
    <p>{{price}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: ""
    };
  }
};
</script>

We set the currency symbol to the currency prop.

separator is the thousands separator.

v-model binds the input value to the price state when it’s a valid number.

We can restrict the valid range with min and max and set the placeholder prop with a value for the placeholder.

Conclusion

v-lazy-image lets us add lazy load images.

vue-shortkey lets us add keyboard shortcut handling.

rackbeat-vue-numeric lets us add numeric inputs to our app.

vue-prism-editor is an easy to add code editor that we can use in our Vue app.

Categories
Top Vue Packages

Top Vue Packages for Adding Carousels, Toasts, and Dropdowns

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how the best packages for adding a carousel, displaying toasts, and add dropdowns.

Vue Carousel

We can use the Vue Carousel component for adding a slideshow to our app.

To install it, we run:

npm i vue-carousel

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueCarousel from "vue-carousel";

Vue.use(VueCarousel);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <carousel :per-page="1" :navigate-to="2" :mouse-drag="false">
      <slide v-for="n in 10" :key="n">Slide {{n}}</slide>
    </carousel>
  </div>
</template>

<script>
export default {
  data() {}
};
</script>

We set navigate-to to navigate the slide with the given index.

per-page is the number of slides per page.

mouse-drag is false so we can’t navigate by dragging the mouse.

Inside the carousel component, we add the slide component to add the slides.

It has many other options and also supports transitions.

Options include setting the pagination style, navigation labels, autoplay, and more.

Vue Toastification

Vue Toastification lets us add toasts with various styles.

To use it, we first install the package by writing:

npm i vue-toastification

Then we can register the plugin and import the CSS:

import Vue from "vue";
import App from "./App.vue";
import Toast from "vue-toastification";
import "vue-toastification/dist/index.css";

Vue.use(Toast);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

Then we can display a toast by writing:

<template>
  <div></div>
</template>

<script>
export default {
  mounted() {
    this.$toast("toast!");
  }
};
</script>

Now we should get a popup with the message we passed into this.$toast displayed.

We can also write:

<template>
  <div></div>
</template>

<script>
export default {
  mounted() {
    this.$toast("My toast", {
      timeout: 2000
    });
  }
};
</script>

to add a delay before displaying the toast.

The delay is in milliseconds.

It also works with Nuxt and the composition API.

vue-select

vue-select lets us add a drop-down that is more flexible than the regular select element.

To use it, we install it by running:

npm i vue-select

Then we can use it by registering the plugin and import the built-in styles:

import Vue from "vue";
import App from "./App.vue";
import vSelect from "vue-select";
import "vue-select/dist/vue-select.css";

Vue.component("v-select", vSelect);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

And we can add the dropdown with the v-select component:

<template>
  <div>
    <v-select v-model="country" :options="['Canada', 'United States']"></v-select>
    <p>{{country}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      country: ""
    };
  }
};
</script>

It binds to country via v-model , and it takes options via the options prop.

We can add a label that’s different from the value by writing:

<template>
  <div>
    <v-select v-model="country" label="name" :options="countries"></v-select>
    <p>{{country}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      country: "",
      countries: [{ name: "Canada", code: "ca" }, { name: "US", code: "us" }]
    };
  }
};
</script>

The label is displayed to the user.

We can even add pagination:

<template>
  <div>
    <v-select
      v-model="country"
      label="country"
      :options="paginated"
      @search="query => search = query"
      :filterable="false"
    >
      <li slot="list-footer">
        <button @click="offset -= 10" :disabled="!hasPrevPage">Prev</button>
        <button @click="offset += 10" :disabled="!hasNextPage">Next</button>
      </li>
    </v-select>
    <p>{{country}}</p>
  </div>
</template>

<script>
export default {
  data: () => ({
    countries: [
      {
        country: "Afghanistan"
      },
      {
        country: "Albania"
      },
      {
        country: "Algeria"
      },
      {
        country: "American Samoa"
      },
      {
        country: "Andorra"
      },
      {
        country: "Angola"
      },
      {
        country: "Anguilla"
      },
      {
        country: "Antarctica"
      },
      {
        country: "Antigua and Barbuda"
      },
      {
        country: "Argentina"
      },
      {
        country: "Armenia"
      }
    ],
    search: "",
    offset: 0,
    limit: 10,
    country: ""
  }),
  computed: {
    filtered() {
      return this.countries.filter(country =>
        country.country.includes(this.search)
      );
    },
    paginated() {
      return this.filtered.slice(this.offset, this.limit + this.offset);
    },
    hasNextPage() {
      const nextOffset = this.offset + 10;
      return Boolean(
        this.filtered.slice(nextOffset, this.limit + nextOffset).length
      );
    },
    hasPrevPage() {
      const prevOffset = this.offset - 10;
      return Boolean(
        this.filtered.slice(prevOffset, this.limit + prevOffset).length
      );
    }
  }
};
</script>

We have the search event handler to set the search value of the dropdown.

We have a footer with the pagination buttons.

They call methods to get the slice of the array that we want displaying for the page.

We display the next or prev buttons if there are no next or previous pages respectively.

Conclusion

Vue Carousel is an easy to use carousel for Vue apps.

Vue Toastification lets us add toasts easily.

vue-select is a dropdown component that’s much more powerful than a select element.

Categories
Top Vue Packages

Top Vue Packages for Adding Currency Input, Menu, Icons, and Resizable Elements

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how the best packages for adding a Stripe like menu, numeric currency input, icons, and resizable elements.

vue-stripe-menu

vue-stripe-menu lets us add a Stripe like menu to our app.

To install it, we run:

npm i vue-stripe-menu

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueStripeMenu from "vue-stripe-menu";
import "vue-stripe-menu/dist/vue-stripe-menu.css";
Vue.use(VueStripeMenu);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <vsm-menu
    :menu="menu"
    :base-width="380"
    :base-height="400"
    :screen-offset="10"
    element="header"
    @open-dropdown="onOpenDropdown"
    @close-dropdown="onCloseDropdown"
  >
    <template #default="{ item }">
      <div class="wrap-content">
        <div class="wrap-content__block">Header: {{ item.title }}</div>
        <div class="wrap-content__item">{{ item }}</div>
      </div>
    </template>
    <template #before-nav>
      <li class="vsm-section logo-section">
        <img src="http://placekitten.com/100/100" alt="logo">
      </li>
    </template>
    <template #title="data">{{ data.item.title }}</template>
    <template #after-nav>
      <li class="vsm-section vsm-mob-hide">
        <button>My Button</button>
      </li>
      <vsm-mob>Mobile Content</vsm-mob>
    </template>
  </vsm-menu>
</template>

<script>
export default {
  data() {
    return {
      menu: [
        {
          title: "App",
          dropdown: "app",
          element: "span",
          attributes: {
            class: ["my-class1", { "my-class2": true }],
            "data-big": "yes"
          },
          listeners: {
            mouseover: evt => {
              console.log("news hover", evt);
            }
          },
          new_section: false
        },
        {
          title: "External Link",
          attributes: {
            href: "https://example.com",
            target: "_blank"
          }
        }
      ]
    };
  },
  methods: {
    onOpenDropdown() {
      console.log("onOpenDropdown");
    },
    onCloseDropdown() {
      console.log("onCloseDropdown");
    }
  }
};
</script>

We get an App link that displays something on hover.

The External Link link displays a link that we can click.

We also have a button.

item has the item.

We can also get the logo.

The menu is responsive so it displays different content when the screen is narrow.

We can style it the way we like.

There are slots to populate various items.

The default slot has the header items.

title has the title.

after-nav has the button.

vue-numeric-currency

vue-numeric-currency lets us add a currency input to our Vue app.

To use it, we first install it by writing:

npm i vue-numeric-currency

Then we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueNumeric from "vue-numeric-currency";

Vue.use(VueNumeric);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <vue-numeric currency="$" separator="," v-model="price"></vue-numeric>
    <p>{{price}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      price: 0
    };
  }
};
</script>

We add the vue-numeric component to our App component.

currency has the currency.

separator is the thousands separator.

v-model binds to the price state.

The binding is only done if we type a number.

We can restrict the range with the min and max props.

precision lets us change the number of decimal digits.

placeholder lets us change the placeholder.

We can also use the autoselect prop to auto-select the entered text when we focus on the input.

vue-resizable

vue-resizable lets us creates a draggable and resizable component.

To install it, we can run:

npm i vue-resizable

Then we can make a draggable component by writing:

<template>
  <vue-resizable>
    <div class="resizable-content"></div>
  </vue-resizable>
</template>

<script>
import VueResizable from "vue-resizable";

export default {
  components: { VueResizable }
};
</script>

<style scoped>
.resizable-content {
  height: 100%;
  width: 100%;
  background-color: green;
}
</style>

We used the vue-resizable component to wrap anything that’s draggable and resizable inside.

The height and width has to be set as percentages or vw or vh to let the us change its size.

It emits various events. It emits events when the size changes, or when it’s dragged.

It also emits an event when it’s mounted.

vue-unicons

vue-unicons is a useful set of icons we can use in our app.

To install it, we run:

npm i vue-unicons

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import Unicon from "vue-unicons";
import { uniLayerGroupMonochrome, uniCarWash } from "vue-unicons/src/icons";

Unicon.add([uniLayerGroupMonochrome, uniCarWash]);
Vue.use(Unicon);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <unicon name="car-wash" fill="green"></unicon>
</template>

<script>
export default {};
</script>

We register the icon in main.js and used it in App.vue .

Conclusion

vue-stripe-menu lets us add a Stripe-like menu to our app.

vue-numeric-currency lets us add a numeric currency input with various options.

To add a resizable element, we can use the vue-resizable package.

vue-unicons gives us a set of icons we can use in our Vue app.

Categories
Top Vue Packages

Top Vue Packages for Grid Layout, Watching Intersections, Styled Components, and Tag Input

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how the best packages for adding grid layout, watching intersections, adding styled-components, and adding tags.

vue-grid-layout

vue-grid-layout lets us add grid to our app with cells that are resizable.

To use it, first we install it by running:

npm i vue-grid-layout

Then we write:

<template>
  <div>
    <grid-layout
      :layout.sync="layout"
      :col-num="12"
      :row-height="30"
      :is-draggable="true"
      :is-resizable="true"
      :is-mirrored="false"
      :vertical-compact="true"
      :margin="[10, 10]"
      :use-css-transforms="true"
    >
      <grid-item
        v-for="item in layout"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        :key="item.i"
      >{{item.i}}</grid-item>
    </grid-layout>
  </div>
</template>

<script>
import VueGridLayout from "vue-grid-layout";
const layout = [
  { x: 0, y: 0, w: 2, h: 2, i: "0" },
  { x: 2, y: 0, w: 2, h: 4, i: "1" },
  { x: 4, y: 0, w: 2, h: 5, i: "2" }
];

export default {
  components: {
    GridLayout: VueGridLayout.GridLayout,
    GridItem: VueGridLayout.GridItem
  },
  data() {
    return {
      layout
    };
  }
};
</script>

to add the grid.

grid-layout has the grid.

grid-item has the grid items.

We set the is-draggable prop to make the items draggable.

is-resizable prop makes the items resizable.

is-mirrored set to false indicates that we don’t want to reverse the order of the items.

row-height has the row height.

use-css-transforms set to true means we use CSS to transform items.

col-num has the number of columns on the grid.

layout has the layout array.

We set the x and y coordinates with the properties of the same name in the entry.

Width and height are set by w and h .

i has the content.

Vue Intersect

Vue Intersect adds the intersection observer API to our Vue app.

To use it, we install it by running:

npm i vue-intersect

Then we can use it by writing:

<template>
  <intersect @enter="msg = 'Intersected'" @leave="msg = 'Not intersected'">
    <div>{{ msg }}</div>
  </intersect>
</template>

<script>
import Intersect from "vue-intersect";

export default {
  components: { Intersect },
  data() {
    return {
      msg: ""
    };
  }
};
</script>

We imported the component and then we’ll see if the element intersecting the viewport as indicated by the messages that are set by the enter and leave events.

vue-styled-components

vue-styled-components lets us create styled-components with a few lines of code./

To install it, we run:

npm i vue-styled-components

Then we can use it by writing:

<template>
  <div>
    <styled-title>hello</styled-title>
  </div>
</template>

<script>
import styled from "vue-styled-components";

const StyledTitle = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: green;
`;

export default {
  components: {
    "styled-title": StyledTitle
  }
};
</script>

We created the StyledTitle component by passing in a string with the styles to the styled.h1 template tag.

Styled components can accept props to change their styling:

<template>
  <div>
    <styled-title primary>hello</styled-title>
  </div>
</template>

<script>
import styled from "vue-styled-components";

const h1Props = { primary: Boolean };

const StyledTitle = styled("h1", h1Props)`
  font-size: 1em;
  margin: 1em;

background: ${props => (props.primary ? "blue" : "white")};
  color: ${props => (props.primary ? "white" : "blue")};
`;

export default {
  components: {
    "styled-title": StyledTitle
  }
};
</script>

We made the StyledTitle component take the primary prop.

vue-tags-input

vue-tags-input lets us input tags. To install it, we run:

npm i @johmun/vue-tags-input

Then we can use it by registering the component and putting the vue-tags-input into our template:

<template>
  <div>
    <vue-tags-input v-model="tag" :tags="tags" @tags-changed="newTags => tags = newTags"/>
    <p>{{tag}}</p>
    <p>{{tags}}</p>
  </div>
</template>

<script>
import VueTagsInput from "@johmun/vue-tags-input";

export default {
  components: {
    VueTagsInput
  },
  data() {
    return {
      tag: "",
      tags: []
    };
  }
};
</script>

It emits the tags-changed event that has all the tags, and we set that as the tags.

The tag state has the tag that’s currently being entered.

Conclusion

vue-grid-layout lets us add a draggable and resizable grid layout easily.

Vue Intersect brings the intersection observer API to our Vue app.

vue-styled-components lets us add styled-components easily.

vue-tags-input is an easy to use tag input.

Categories
Top Vue Packages

Top Vue Packages for Adding a Slider, Text Slider, Datepicker, and Intersection Detection

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how the best packages for adding a slider, datepicker, timeline, and intersection detection.

vue-textra

vue-textra lets us add a text slider to our Vue app.

To install it, we run:

npm i vue-textra

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import Textra from "vue-textra";

Vue.use(Textra);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <textra :data='words' :timer="4" filter="flash" />
  </div>
</template>

<script>

export default {
  data(){
    return {
      words: ['foo', 'bar', 'baz']
    }
  }
};
</script>

We register the plugin.

Then we add the textra component that displayed each string in the array one by one.

timer is the time to display each string in seconds.

filter is the effect when transitioning between text.

We can make the component loop infinitely with the infinite prop.

Other filter effects include simple , bottom-top , top-bottom , right-left , left-right , press , scale , flash and flip .

VueWaypoint

VueWaypoint lets us run functions based on elements’ positions based on viewport.

To install it, we run:

npm i vue-waypoint

Then we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueWaypoint from "vue-waypoint";

Vue.use(VueWaypoint);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <div
      v-for="n in 50"
      :key="n"
      v-waypoint="{ active: true, callback: onWaypoint, options: intersectionOptions }"
    >{{n}}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      intersectionOptions: {
        root: null,
        rootMargin: "0px 0px 0px 0px",
        threshold: [0, 1]
      }
    };
  },
  methods: {
    onWaypoint({ going, direction }) {
      if (going === this.$waypointMap.GOING_IN) {
        console.log("waypoint going in!");
      }

      if (direction === this.$waypointMap.DIRECTION_TOP) {
        console.log("waypoint going top!");
      }
    }
  }
};
</script>

We register the plugin in main.js .

Then we use the v-waypoint directive to watch the element’s entry and exit from the viewport.

this.$waypointMap.GOING_IN indicates it’s going inside the viewport.

And DIRECTION_TOP means it’s moving to the top.

It can also detect the direction to the right, bottom, and left.

vue-pipeline

vue-pipeline lets us add a pipeline to display to our Vue app.

We can install it by running:

npm install vue-pipeline

Then we can write:

main.js

<template>
  <div id="app">
    <vue-pipeline :data="data"></vue-pipeline>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: [
        {
          name: "Start",
          hint: "Start",
          status: "start",
          next: [{ index: 1, weight: 2 }]
        },
        {
          name: "eat",
          hint: "eat",
          status: "success",
          next: [{ index: 2, weight: 0 }, { index: 4, weight: 2 }]
        },
        {
          name: "drink",
          hint: "drink",
          status: "failure",
          next: [{ index: 3, weight: 0 }]
        },
        {
          name: "sleep",
          hint: "sleep",
          status: "paused",
          next: [{ index: 4, weight: 0 }]
        },
        { name: "end ", hint: "2m23s", status: "end", next: [] }
      ]
    };
  }
};
</script>

We register the component and then add the vue-pipeline component to our component.

The data is an array with various properties.

name is the name of the item. hint is displayed on hover.

status is displayed as an icon. next indicates the next step.

Other props includes xstep to change the horizontal position from the previous node.

ystep changes the vertical position from the previous node.

lineStyle is a string for the line style. It can be default , bessel , or line .

vuejs-datepicker

We can add use vuejs-datepicker to add a date picker to our app.

To install it, we can run:

npm i vuejs-datepicker

Then we can use it by adding:

<template>
  <div id="app">
    <datepicker v-model="date"></datepicker>
    <p>{{date}}</p>
  </div>
</template>

<script>
import Datepicker from "vuejs-datepicker";

export default {
  data() {
    return {
      date: undefined
    };
  },
  components: {
    Datepicker
  }
};
</script>

We register the Datepicker component, then we add it to the template.

We set the v-model with the date state to bind it to that.

Now when we select a date, we get the date displayed.

It supports changing many parts of the date picker, including the icons, buttons, setting it to required or disabled, changing to display Monday first, and much more.

Conclusion

vuejs-datepicker lets us add a datepicker.

vue-pipeline lets us add a timeline display.

vue-textra lets us add a text slider.

VueWaypoint adds intersection detection to our app.