Vue Props Validation - Best Practices

Cover image

Passing data down through component props is a common Vue pattern. How do we validate props & what are some best-practices when using them? 🧐

In this tutorial, we will cover best-practices props validation and things to watch out for when passing data down from one component to another.

Overview

Let's have a look at the bigger picture first and then dig deeper. 😎

All Kind Of Props

A long list of props with all sort of validation criteria:

  props: {
    // Basic type check (`null` and `undefined` values will pass any type validation)
    luckyNumber: Number,
    // Multiple possible types
    flexibleProp: [String, Number],
    // Required string
    name: {
      type: String,
      required: true
    },
    // Number with a default value
    percentage: {
      type: Number,
      default: 100
    },
    // Object with a default value
    profile: {
      type: Object,
      // Object or array defaults must be returned from
      // a factory function
      default: function() {
        return { name: "Mr. 007", email: "james@bond.io" };
      }
    },
    // Custom validator function
    season: {
      validator: function(value) {
        // The value must match one of these strings
        return ["winter", "summer", "autumn", "spring"].includes(value);
      }
    },
    // Array with a type-check validator function.
    skills: {
      type: Array,
      validator: prop => prop.every(e => typeof e === "string")
    },
    // Imported custom validator function
    phoneNumber: {
      validator: prop => phoneNumberValidator(prop)
    }
  }

Let's explore the different use-cases applied here...

Basic Validation

A simple example of how we can add a number type to a prop:

props: {
  luckyNumber: Number,
}

Did you notice the prop's name was a camel-cased?

Camel-Case => Kebab-Case

Vue Automatically translates any camel-cased prop into kebab-case when used in a template.

Here is how you would pass the data in the previous example of luckyNumber:

<!-- parent component -->
<game-of-life :lucky-number="7"></game-of-life>

And here is how you would use the prop in the child component's template

<!--  child component -->
<template>
  <h1>{{ luckyNumber }}</h1>
</template>

Now, let's cover some of the basic validation types...

Basic Type Validation

Out of the box, Vue allows these native types:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

So you can do things like this...

<script>
export default {
  props: {
    name: String,
    luckyNumber: Number,
    isLucky: Boolean,
    luckyPlaces: Array,
    luck: Object,
    birthday: Date,
    luckCallback: Function,
    friendsPromise: Promise // or any other custom constructor
  }
};
</script>

In addition, you can create your own custom constructors!

Function Constructor Validation

I don't use often that validation pattern myself but it definitely can be handy in certain use-cases.

Here is a simple demonstration:

<script>
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

export default {
  props: {
    author: Person
  }
};
</script>

You may have also noticed earlier that there were some validator functions used in the props list. Let's have a closer look at these...

Validators

The validator property allows you to create your own custom validator function.

They are very handy for example when validating items of an array or object's values.

props: {
    // Custom validator function
    season: {
      validator: function (value) {
        // The value must match one of these strings
        return ['winter', 'summer', 'autumn', 'spring'].includes(value)
      }
    },
    // Array with a type-check validator function.
    skills: {
      type: Array,
      validator: (prop) => prop.every(e => typeof e === 'string'),
    }
}

You can also have shared custom validation functions that you import to different components, here is an example of of a phone number validator...

props: {
  // Imported custom validator function
  phoneNumber: {
    validator: prop => phoneNumberValidator(prop);
  }
}
// Phone Number Validator Fn
export function phoneNumberValidator(data) {
  const phoneNumberRegex = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im;

  return data.match(phoneNumberRegex);
}

Default Prop Values

Vue allows you to define a default value for a prop.

// The user may not provide a value, so we should just in case
props: {
  // Object with a default value
  profile: {
    type: Object,
    // Object or array defaults must be returned from
    // a factory function
    default: function () {
      return { name: 'Mr. 007', email: 'james@bond.io' }
    }
  },
  birthday: {
    type: Date,
    default: new Date('July 10, 1856'), // forever young
  }
}

Note, for objects & arrays the default values must be returned through a function as you can see above.

When Validation Fails

If you happen to pass the wrong type to a prop, you should see in the console something similar to this...

Vue prop type validation error message example in the console.

Now you should know your way around props validations, time for some best-practices...

Best Practices 👌

Here are some guidelines I follow myself:

  • Always validate your props.
  • Always have a default value for non-required props.
  • Don't add a default value for required props.
  • Never mutate the prop, it may affect the parent's state in case of mutating objects & arrays.
  • Validator & default functions should be stateless since they run before the component is created.
  • Avoid declaring more than one type to a prop.

Resources

That is it, now you can validate your props like a pro! 🔥

Support us

Enjoyed the article? Share the summary thread on twitter.



Author image

Learn how to build scalable, fast and accessible web applications.

Follow us on Twitter

hello@nordschool.com