vue logo

Vuetensils 0.4: awesome components and helpful directives

The latest release of Vuetensils is out, and with it comes some exciting improvements including 2 brand new components (VFile, VResize), and some handy directives (autofocus, clickout, copy). These additions will make it faster and easier to create robust, accessible UIs with Vue.js with your own designs, and no bloat.

VFile – custom, accessible file selection

First up is a look at the VFile component. By default, it looks and behaves like an HTML 5 file input, and that’s because under the hood it is one. However, it goes a step further by allowing developers to easily create custom drag and drop file selectors while maintaining accessible UIs.

Take for example the following:

<template>
  <div id="app">
    <VFile v-model="files" label="File selection:" multiple>
      <template #default="{ droppable }">
        <div class=" dropzone " :class=" { droppable, selected: files.length } " aria-hidden="true">
          <p v-if="droppable">Go on, you can let go.</p>

          <div v-else-if="files.length">
            <p>{{ files.length }} file(s) selected:</p>
            <ul>
              <li v-for="(file, index) in files" :key="index">{{ file.name }}</li>
            </ul>
          </div>

          <p v-else>Select files or drag and drop them here.</p>
        </div>
      </template>
    </VFile>
    
    <button v-if="files.length" @click="files = []" class=" clear _6 ">Clear files</button>
  </div>
</template>

<script>
import { VFile } from "vuetensils";

export default {
  components: {
    VFile
  },

  data: () => ({
    files: []
  })
};
</script>

Edit Vuetensils VFile

Users get a nice visible interface for dragging and dropping files or opening the file selection options, and any users relying on keyboards to navigate do not miss out on the experience.

Nice!

VResize – container queries made easy

Not all Vuetensils components need to focus on accessibility. Some simply make it easier to develop complex UIs. With VResize, for example, we can customize our components based on their width and height.

Now, you might be thinking that CSS media queries solve the issue of providing different layouts at different sizes. However, the layout is not always based on screen size, but on the size of the element itself. This is where “container queries” come into play.

Container queries are useful in the following scenario:

I have a component that should stack it’s contents when it’s less than 500px wide. If my screen is 900px wide and I only have this component, no problem. But if my layout is split in two, suddenly my screen is still 900px, but I only have 450px to work with, and my component ends up looking like butt. A smooshed butt at that.

Let’s take a look at that with a live example:

<template>
  <div id="app">
    <p>Resize the browser to see changes</p>
    <div class=" grid ">
      <VResize>
        <template #default="{ width }">
          <div class=" bio " :class=" { small: width < 450 } ">
            <img src="https://www.fillmurray.com/200/200">
            <p>This content is {{ width }}px wide.</p>
          </div>
        </template>
      </VResize>

      <VResize>
        <template #default="{ width }">
          <div class=" bio " :class=" { small: width < 450 } ">
            <img src="https://www.fillmurray.com/200/200">
            <p>This content is {{ width }}px wide.</p>
          </div>
        </template>
      </VResize>

      <VResize>
        <template #default="{ width }">
          <div class=" bio " :class=" { small: width < 450 } ">
            <img src="https://www.fillmurray.com/200/200">
            <p>This content is {{ width }}px wide.</p>
          </div>
        </template>
      </VResize>

      <VResize>
        <template #default="{ width }">
          <div class=" bio " :class=" { small: width < 450 } ">
            <img src="https://www.fillmurray.com/200/200">
            <p>This content is {{ width }}px wide.</p>
          </div>
        </template>
      </VResize>
    </div>
  </div>
</template>

<script>
import { VResize } from "vuetensils";

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

Edit Vuetensils VResize

Autofocus directive

There are some scenarios where you reveal a text input and you expect the next user behavior to interact with that input. The best experience for the user is for the text input to receive focus immediately. Think of when you go to Google, the search input is automatically focused, so you don’t have to click into it first.

With Vutensils’ autofocus directive you can achieve the same thing within your Vue component like so:

<template>
  <label>
    Search for something
    <input type="search" v-autofocus />
  </label>
</template>

Clickout directive

Another helpful directive, Vuetensils’ clickout directive let’s developers easily attach functionality to a click event that happens outside of a specific component:

<template>
  <div v-clickout="onClickout">Click outside and see.</div>
</template>

<script>
export default {
  methods: {
    onClickout() {
      alert('you clicked outside the div')
    }
  }
}

Copy directive

Last but not least is the copy directive. Users are regularly presented with text that they need to copy and paste somewhere else. More and more often, we are seeing convenient click-to-copy functionality tied to these text elements because it makes for a good user experience.

With the copy directive, we can accomplish that feature very easily by simply doing the following:

<template>
  <button v-copy="`hello world`">Click to copy</button>
</template>