Tags

Full width

Zoom: 50% | 100% →

Full Width Tags

You want to show a bunch of text but don't want it to take up too much real estate. So you decided to overflow horizontally. Vue Horizontal to the rescue!

import=recipes/tags/recipes-tags-full.vue padding=0 zoom
<template>
  <main>
    <vue-horizontal class="horizontal" :displacement="0.5" :button-between="false">
      <template v-slot:btn-prev>
        <svg class="btn-left" viewBox="0 0 24 24">
          <path d="m9.8 12 5 5a1 1 0 1 1-1.4 1.4l-5.7-5.7a1 1 0 0 1 0-1.4l5.7-5.7a1 1 0 0 1 1.4 1.4l-5 5z"/>
        </svg>
      </template>

      <template v-slot:btn-next>
        <svg class="btn-right" viewBox="0 0 24 24">
          <path d="m14.3 12.1-5-5a1 1 0 0 1 1.4-1.4l5.7 5.7a1 1 0 0 1 0 1.4l-5.7 5.7a1 1 0 0 1-1.4-1.4l5-5z"/>
        </svg>
      </template>

      <div class="item" v-for="tag in tags" :key="tag.name">
        <button class="tag">
          {{ tag.name }}
        </button>
      </div>
    </vue-horizontal>

    <article>
      <h3>Full Width Tags</h3>
      <p>You want to show a bunch of text but don't want it to take up too much real estate.
        So you decided to overflow horizontally. Vue Horizontal to the rescue!</p>
    </article>
  </main>
</template>

<script>
export default {
  data() {
    return {
      tags: [
        {name: 'VueJS'}, {name: 'Nuxt'}, {name: 'Gridsome'}, {name: 'VuePress'},
        {name: 'ReactJS'}, {name: 'Next'}, {name: 'Gatsby'}, {name: 'Node.js'},
        {name: 'Typescript'}, {name: 'Javascript'}, {name: 'Webpack'}, {name: 'HTML'}, {name: 'CSS'},
        {name: 'Java'}, {name: 'Spring Boot'}, {name: 'Spring Framework'}, {name: 'Gradle'}, {name: 'Maven'},
        {name: 'Python'}, {name: 'Flutter'}, {name: 'Terraform'},
        {name: 'CircleCI'}, {name: 'IntelliJ'},
        {name: 'GitHub'},
      ]
    }
  }
}
</script>

<style scoped>
.tag {
  font-weight: 600;
  font-size: 15px;
  color: #777;
  border: 1px solid #e2e8f0;
  border-radius: 3px;
  line-height: 1;
  padding: 8px 24px;
  margin-right: 16px;
}

.btn-left, .btn-right {
  padding: 6px;
  height: 100%;
}

.btn-left {
  background: linear-gradient(to left, #ffffff00 0, #fff 50%, #fff);
}

.btn-right {
  background: linear-gradient(to right, #ffffff00 0, #fff 50%, #fff);
}

main {
  padding: 24px;
}

@media (min-width: 768px) {
  main {
    padding: 48px;
  }
}

article {
  margin-top: 24px;
}
</style>

Tight space

Zoom: 50% | 100% →

Tight Spacing Tags

You want to put something on the left or right of the horizontal space.

import=recipes/tags/recipes-tags-tight.vue padding=0 zoom
<template>
  <main>
    <div class="search">
      <div class="field">
        <label>
          <input placeholder="Search">
        </label>
      </div>

      <vue-horizontal class="horizontal" :displacement="0.9" :button-between="false" snap="center">
        <template v-slot:btn-prev>
          <svg class="btn-left" viewBox="0 0 24 24">
            <path d="m9.8 12 5 5a1 1 0 1 1-1.4 1.4l-5.7-5.7a1 1 0 0 1 0-1.4l5.7-5.7a1 1 0 0 1 1.4 1.4l-5 5z"/>
          </svg>
        </template>

        <template v-slot:btn-next>
          <svg class="btn-right" viewBox="0 0 24 24">
            <path d="m14.3 12.1-5-5a1 1 0 0 1 1.4-1.4l5.7 5.7a1 1 0 0 1 0 1.4l-5.7 5.7a1 1 0 0 1-1.4-1.4l5-5z"/>
          </svg>
        </template>

        <div class="item" v-for="tag in tags" :key="tag.name">
          <button class="tag">
            {{ tag.name }}
          </button>
        </div>
      </vue-horizontal>
    </div>

    <article>
      <h3>Tight Spacing Tags</h3>
      <p>You want to put something on the left or right of the horizontal space.</p>
    </article>
  </main>
</template>

<script>
export default {
  data() {
    return {
      tags: [
        {name: 'VueJS'}, {name: 'Nuxt'}, {name: 'Gridsome'}, {name: 'VuePress'},
        {name: 'ReactJS'}, {name: 'Next'}, {name: 'Gatsby'}, {name: 'Node.js'},
        {name: 'Typescript'}, {name: 'Javascript'}, {name: 'Webpack'}, {name: 'HTML'}, {name: 'CSS'},
        {name: 'Java'}, {name: 'Spring Boot'}, {name: 'Spring Framework'}, {name: 'Gradle'}, {name: 'Maven'},
        {name: 'Python'}, {name: 'Flutter'}, {name: 'Terraform'},
        {name: 'CircleCI'}, {name: 'IntelliJ'},
        {name: 'GitHub'},
      ]
    }
  }
}
</script>

<style scoped>
.search {
  display: flex;
}

input {
  font-weight: 600;
  font-size: 17px;
  padding: 4px 16px;
  border: 1px solid #e2e8f0;
  border-radius: 3px;
  width: 100%;
}

.field {
  padding-right: 24px;
  flex-shrink: 0;
  width: 65%;
}

.horizontal {
  flex-shrink: 1;
  flex-grow: 1;
  width: 20%;
}

.tag {
  font-weight: 600;
  font-size: 15px;
  color: #777;
  border: 1px solid #e2e8f0;
  border-radius: 3px;
  line-height: 1;
  height: 100%;
  padding-left: 18px;
  padding-right: 18px;
  margin-right: 16px;
}

.btn-left, .btn-right {
  padding: 8px 2px;
  height: 100%;
}

.btn-left {
  background: linear-gradient(to left, #ffffff00 0, #fff 80%, #fff);
}

.btn-right {
  background: linear-gradient(to right, #ffffff00 0, #fff 80%, #fff);
}

main {
  padding: 24px;
}

@media (min-width: 768px) {
  main {
    padding: 48px;
  }
}

article {
  margin-top: 24px;
}
</style>

Mouse Wheel Event

Vertical scroll trigger horizontal scroll.

Zoom: 50% | 100% →

Mouse Wheel Scroll Event

Usually you won't want to enable vertical scroll as well as horizontal scroll on any horizontal content on your web as it will interfere with the nature flow of the content. User expectation of vertical scroll is that the content scroll vertically and not try to act otherwise. But if the content is situated at the edge of the y axis (top/bottom) it might make sense to enable that user experience as it will not be interfering with the nature flow of the content.

I personally would still stick with just the navigation button.

import=recipes/tags/recipes-tags-scroll-wheel.vue padding=0 zoom
<template>
  <main>
    <div @wheel="onWheel">
      <vue-horizontal ref="horizontal" class="horizontal"
                      snap="none" :displacement="0.5" :button-between="false" @scroll="onScrollDebounce">
        <template v-slot:btn-prev>
          <svg class="btn-left" viewBox="0 0 24 24">
            <path d="m9.8 12 5 5a1 1 0 1 1-1.4 1.4l-5.7-5.7a1 1 0 0 1 0-1.4l5.7-5.7a1 1 0 0 1 1.4 1.4l-5 5z"/>
          </svg>
        </template>

        <template v-slot:btn-next>
          <svg class="btn-right" viewBox="0 0 24 24">
            <path d="m14.3 12.1-5-5a1 1 0 0 1 1.4-1.4l5.7 5.7a1 1 0 0 1 0 1.4l-5.7 5.7a1 1 0 0 1-1.4-1.4l5-5z"/>
          </svg>
        </template>

        <div class="item" v-for="tag in tags" :key="tag.name">
          <button class="tag">
            {{ tag.name }}
          </button>
        </div>
      </vue-horizontal>
    </div>

    <article>
      <h3>Mouse Wheel Scroll Event</h3>
      <p>
        Usually you won't want to enable vertical scroll as well as horizontal scroll on any horizontal content on your
        web as it will interfere with the nature flow of the content.
        User expectation of vertical scroll is that the content scroll vertically and not try to act otherwise.
        But if the content is situated at the edge of the y axis (top/bottom) it might make sense to enable that
        user experience as it will not be interfering with the nature flow of the content.
      </p>

      <p>
        I personally would still stick with just the navigation button.
      </p>
    </article>
  </main>
</template>

<script>
export default {
  data() {
    return {
      tags: [
        {name: 'VueJS'}, {name: 'Nuxt'}, {name: 'Gridsome'}, {name: 'VuePress'},
        {name: 'ReactJS'}, {name: 'Next'}, {name: 'Gatsby'}, {name: 'Node.js'},
        {name: 'Typescript'}, {name: 'Javascript'}, {name: 'Webpack'}, {name: 'HTML'}, {name: 'CSS'},
        {name: 'Java'}, {name: 'Spring Boot'}, {name: 'Spring Framework'}, {name: 'Gradle'}, {name: 'Maven'},
        {name: 'Python'}, {name: 'Flutter'}, {name: 'Terraform'},
        {name: 'CircleCI'}, {name: 'IntelliJ'},
        {name: 'GitHub'},
      ],
      scrollDebounceId: null,
      left: 0
    }
  },
  methods: {
    onScrollDebounce({left}) {
      clearTimeout(this.scrollDebounceId);
      this.scrollDebounceId = setTimeout(() => {
        this.left = left
      }, 500);
    },
    onWheel(event) {
      this.left = this.left + event.deltaY
      this.left = this.left + event.deltaX
      this.$refs.horizontal.scrollToLeft(this.left, 'auto')
    },
  }
}
</script>

<style scoped>
.horizontal {
  margin: 4px 8px;
}

.tag {
  font-weight: 600;
  font-size: 15px;
  color: #777;
  border: 1px solid #e2e8f0;
  border-radius: 3px;
  line-height: 1;
  padding: 8px 24px;
  margin: 8px;
}

.btn-left, .btn-right {
  padding: 12px;
  height: 100%;
}

.btn-left {
  background: linear-gradient(to left, #ffffff00 0, #fff 50%, #fff);
}

.btn-right {
  background: linear-gradient(to right, #ffffff00 0, #fff 50%, #fff);
}

article {
  padding: 24px;
}
</style>