Vuetensils 0.10: Vue 3, Vite, Better Forms, And More

This blog post highlights some of the best features coming to Vuetensils in version 0.10. The main focus was on forms and tabs as well as tooling.

I’ve recently published the latest version of Vuetensils and wanted to take some time to share some of the features I’m most excited about.

Vue 3 & Vite

Great news for anyone working with new or newly upgraded projects. Vuetensils now works with Vue 3. We’re leveraging vue-demi to do a little bit of magic to check whether the current running version is Vue 2 or 3.

Unfortunately, this did mean adding my first dependency to the project, but it allows for supporting the most people without having to maintain two projects. This makes it much easier to keep pushing out new features to everyone, not just the folks on Vue 3.

In addition to supporting Vue 3, I also fixed a couple of the blockers in the way of supporting Vite. Vite is an awesome tool that I’ve been developing with (I’m even working on a plugin called Particles CSS), so it’s great to maintain

VInput Improvements

This is probably my favorite new feature. VInput has always supported some validation error logic for classes and state, but I’ve been working on API design for generating validation error messages as well.

Many other libraries do this for you and just decide what the error messages are. That was a bit too much of a design responsibility for this library but I came up with a solution I’m quite happy with.

You can now provide VInput with an errors object and map the appropriate error message to the corresponding validation attribute.

It looks like this:

    label="Pick a number between 1 and 10"
      required: 'This field is required',
      min: (n) => `Must be greater than ${n}`,
      max: (n) => `Must be less than ${n}`,

You can provide a string for the error message to show, or a function that returns a string. The function is provided with the value of the corresponding attribute.

You can read more about this at

In addition to this validation improvement, I also discovered a bug in my original validation logic that has now been fixed. I’m guessing no one had run into that bug yet.

VForm Improvements

A while back, I wrote a blog post called “How to prevent browser refresh, URL changes, or route navigation in Vue“. It’s my most popular post, which makes me feel a little bit embarrassed to realize how long it took for me to add this feature to Vuetensils.

The good news is that today you can have that logic built right into your forms without lifting a finger.

VForm now accepts a preventNavigation prop as a Boolean which will watch your form for any changes. If there are changes made to any of the inputs, the browser will notify the user before leaving unless the form has been submitted.

You can read more about it, or give it a test here:

Another convenience that was added to VForm is the valid and invalid custom events. These work very similar to the default submit event, but they only run when the form is either valid, or invalid (as the names suggest).

  <VForm @valid="onValid" @invalid="onInvalid" novalidate>
      <input name="name" required />

    <button type="submit">

export default {
  methods: {
    onValid(event) {
      console.log('Everything looks good', event)
    onInvalid(event) {
      console.log('Please fix the errors and try again', event)

The idea here is to reduce some of the logic your applications will probably have whenever a form is submitted, and to compartmentalize the functionality.

You can read more about these events here:

VTabs Rewrite

My first take at the VTabs component was ok, but not great. There wasn’t a great option to customize the tab content.

In this new version, I’m much happier with how the tabs are created. It’s all based on custom slot names for the tab and panel.

It looks like this:

    <template #tab-1>Tab 1</template>
    <template #panel-1>
      Here's the content for tabpanel 1.

    <template #tab-2>Tab 2</template>
    <template #panel-2>
      Here's the content for tabpanel 2.

    <template #tab-3>Tab 3</template>
    <template #panel-3>
      Here's the content for tabpanel 3.

The only requirement is that your tab names are prefixed with tab- and panel names are prefixed with panel-. The tabs and panels are connected by sharing the same suffix.

This makes for a pretty simple learning curve, with a lot of flexibility.

VDate i18n

Thanks to some work by Benjamin Courtel, there was a small PR to improve internationalization support in the VDate component. You can now provide custom labels for the navigation buttons.


TypeScript support was already partially existent in the previous version, but hardly in a way that helped anyone. Type definitions for components were not being generated. This was an overlook.

Now that some new tools have been published and I’ve had the time, Vuetensils components ship with type definitions files thanks to vue-typegen by Guillaume Chau.

This should make consuming the library much nicer.

Documentation & Dependencies

I noticed some of my builds were breaking the documentation site so I’ve had to dig in and update dependencies and squash some bugs.

Ultimately, I found the underlying issue and filed a PR. This should mostly only matter to folks that are contributing to the project, as the docs also serve as the development environment.

Thank you so much for reading. If you liked this article, and want to support me, the best ways to do so are to share it, sign up for my newsletter, and follow me on Twitter.

Originally published on