Vue Props

Props is a configuration option in Vue.

With props we can pass data to the components via custom attributes to the component tag.

Pass Data To a Component

Do you remember the example on the previous page where all three components said 'Apple'? With props we can now pass data down to our components to give them different content and make them look different.

Let's make a simple page to show 'Apples', 'Pizza' and 'Rice'.

In the main application file App.vue we create our own attribute 'food-name' to pass a prop with the <food-item/> component tags:

App.vue:

<template>
  <h1>Food</h1>
  <food-item food-name="Apples"/>
  <food-item food-name="Pizza"/>
  <food-item food-name="Rice"/>
</template>

<script></script>

<style>
  #app > div {
    border: dashed black 1px;
    display: inline-block;
    width: 120px;
    margin: 10px;
    padding: 10px;
    background-color: lightgreen;
  }
</style>

Receive Data Inside a Component

To receive the data sent via the 'food-item' attribute from App.vue we use this new 'props' configuration option. We list the attributes received so that our component *.vue file knows about them, and now we can use the props wherever we want in the same way as we use a data property.

FoodItem.vue:

<script>
  export default {
    props: [
      'foodName'
    ]
  }
</script>

Props attributes are written with a dash - to separate words (kebab-case) in the <template> tag, but kebab-case is not legal in JavaScript. So instead we need to write the attribute names as camelCase in JavaScript, and Vue understands this automatically!

Finally, our example with <div> elements for 'Apples', 'Pizza' and 'Rice' looks like this:

Example

App.vue:

<template>
  <h1>Food</h1>
  <food-item food-name="Apples"/>
  <food-item food-name="Pizza"/>
  <food-item food-name="Rice"/>
</template>

FoodItem.vue:

<template>
  <div>
    <h2>{{ foodName }}</h2>
  </div>
</template>

<script>
  export default {
    props: [
      'foodName'
    ]
  }
</script>

<style></style>
Run Example »

Soon we will see how to pass different data types as props attributes to components, but before we do that, let's expand our code with a description of each type of food, and put the food <div> elements inside a Flexbox wrapper.

Example

App.vue:

<template>
  <h1>Food</h1>
  <div id="wrapper">
    <food-item
      food-name="Apples"
      food-desc="Apples are a type of fruit that grow on trees."/>
    <food-item
      food-name="Pizza"
      food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."/>
    <food-item
      food-name="Rice"
      food-desc="Rice is a type of grain that people like to eat."/>
  </div>
</template>

<script></script>

<style>
  #wrapper {
    display: flex;
    flex-wrap: wrap;
  }
  #wrapper > div {
    border: dashed black 1px;
    margin: 10px;
    padding: 10px;
    background-color: lightgreen;
  }
</style>

FoodItem.vue:

<template>
  <div>
    <h2>{{ foodName }}</h2>
    <p>{{ foodDesc }}</p>
  </div>
</template>

<script>
  export default {
    props: [
      'foodName',
      'foodDesc'
    ]
  }
</script>

<style></style>
Run Example »

Boolean Props

We can achieve different functionality by passing props of different data types, and we are able to define rules for how attributes are given when components are created from App.vue.

Let's add a new prop 'isFavorite'. This should be a boolean prop with value either true or false so that we can use it directly with v-show to display a favorite stamp <img> tag if the food is considered a favorite.

To pass props with a data type different to String, we must write v-bind: in front of the attribute we want to pass.

This is how we pass the boolean 'isFavorite' prop from App.vue as an attribute 'is-favorite':

App.vue:

<template>
  <h1>Food</h1>
  <p>My favorite food has a diploma image attached to it.</p>
  <div id="wrapper">
    <food-item
      food-name="Apples"
      food-desc="Apples are a type of fruit that grow on trees."
      v-bind:is-favorite="true"/>
    <food-item
      food-name="Pizza"
      food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."
      v-bind:is-favorite="false"/>
    <food-item
      food-name="Rice"
      food-desc="Rice is a type of grain that people like to eat."
      v-bind:is-favorite="false"/>
  </div>
</template>

We receive the boolean 'isFavorite' prop inside FoodItem.vue and show a favorite stamp if the food is considered favorite:

Example

FoodItem.vue:

<template>
  <div>
    <h2>
      {{ foodName }}
      <img src="/img_quality.svg" v-show="isFavorite">
    </h2>
    <p>{{ foodDesc }}</p>
  </div>
</template>

<script>
  export default {
      props: ['foodName','foodDesc','isFavorite']
  }
</script>

<style>
  img {
    height: 1.5em;
    float: right;
  }
</style>
Run Example »

Images: To make the image in the example above work locally in the project on your machine, open the example above, right click the image, choose "Save Image As..." and save it in the "public" folder in your project.


Props Interface

In the example above, based on the code inside FoodItem.vue, we cannot know for sure that we receive the 'isFavorite' prop, and we cannot know for sure if it is a boolean value. To help us with this we can define the data-type of props we receive, we can set props to be required, and we can even make validation functions to validate the props we receive.

Defining props we receive serves as a documentation for other people if you work in a team, and it provides us with warnings in the console if the rules that we have defined are broken.


Props as an Object

In FoodItem.vue, we comment out how we defined the props in an array to have it as reference, and instead define the props in an object. We can also define the data type of each prop in addition to the prop name, like this:

FoodItem.vue:

<script>
  export default {
    // props: ['foodName','foodDesc','isFavorite']
    props: {
      foodName: String,
      foodDesc: String,
      isFavorite: Boolean
    }
  }
</script>

With props defined in this way, other people can look inside FoodItem.vue and easily see what the component expects.

If a component is created from the parent element (in our case App.vue) and given a prop with the wrong data type, you get a warning in the console, like this:

Screenshot of wrong data type prop warning

Such warnings are useful to let ourselves and others know that a component is not used how it is supposed to, and to tell what is wrong so that we can correct the mistake.


Required Props

To tell Vue that a prop is required we need to define the prop as an object. Let's make the prop 'foodName' required, like this:

FoodItem.vue:

<script>
  export default {
    // props: ['foodName','foodDesc','isFavorite']
    props: {
      foodName: {
        type: String,
        required: true
      },
      foodDesc: String,
      isFavorite: Boolean
    }
  }
</script>

If a component is created from the parent element (in our case App.vue) and a required prop is not defined, you get a warning in the console, like this:

Screenshot of required prop warning

Such warnings are useful to let ourselves and others know that a component is not used how it is supposed to, and to tell what is wrong so that we can correct the mistake.


Default Value

We can set a default value for a prop.

Let's create a default value for the 'foodDesc' prop in the 'FoodItem' component, and then create such an item for rice without defining the 'foodDesc' prop:

Example

App.vue:

<template>
  <h1>Food</h1>
  <p>My favorite food has a diploma image attached to it.</p>
  <div id="wrapper">
    <food-item
      food-name="Apples"
      food-desc="Apples are a type of fruit that grow on trees."
      v-bind:is-favorite="true"/>
    <food-item
      food-name="Pizza"
      food-desc="Pizza has a bread base with tomato sauce, cheese, and toppings on top."
      v-bind:is-favorite="false"/>
    <food-item
      food-name="Rice"
      food-desc="Rice is a type of grain that people like to eat." 
      v-bind:is-favorite="false"/>
  </div>
</template>

FoodItem.vue:

<script>
  export default {
    props: {
      foodName: {
        type: String,
        required: true
      },
      foodDesc: {
        type: String,
        required: false,
        default: 'This is the default description.'
      }
      isFavorite: {
        type: Boolean,
        required: false,
        default: false
      }
    }
  }
</script>
Run Example »

Props Validator Function

We can also define a validator function that decides if the prop value is valid or not.

Such validator functions must return either true or false. When the validator returns false, it means the prop value is invalid. An invalid prop value generates a warning in the browser console when we run our page in developer mode, and the warning is a useful hint to make sure the components are used as intended.

Let's say we want the food description to be a certain length, between 20 and 50 characters. We can add a validator function to make sure the food description provided has a valid length.

FoodItem.vue:

<script>
  export default {
    props: {
      foodName: {
        type: String,
        required: true
      },
      foodDesc: {
        type: String,
        required: false,
        default: 'This is the default description.',
        validator: function(value) {
          if( 20<value.length && value.length<50 ) {
            return true;
          }
          else {
            return false;
          }
        }
      }
      isFavorite: {
        type: Boolean,
        required: false,
        default: false
      }
    }
  }
</script>

Note: If you add the validator code above to your local project, you will get a warning in development mode because the food description for pizza is 65 characters, which is 15 characters longer than the validator function allows.


Modify Props

When a component is created in the parent element we are not allowed to change the value of the prop received in the child element. So inside FoodItem.vue we cannot change the value of the 'isFavorite' prop we get from App.vue. The prop is read-only from the parent, which is App.vue in our case.

But let's say we want the user to be able to change what food is considered favorite by clicking a button. Now there is a need to change the 'isFavorite' prop, but we cannot do it because it is read only.

We are not allowed to change 'isFavorite'. This will generate an error.

methods: {
  toggleFavorite() { 
    this.isFavorite = !this.isFavorite;
  }
}

To get around this we can use the prop to initialize a new data value 'foodIsFavorite', inside FoodItem.vue, like this:

data() {
  return { 
    foodIsFavorite: this.isFavorite
  }
}

And now we can add a method so the user can toggle this new data value:

methods: {
  toggleFavorite() { 
    this.foodIsFavorite = !this.foodIsFavorite;
  }
}

We must also add the toggle button to each food item, and change v-show in the <img> tag to depend on the new data property 'foodIsFavorite'. And to make our example simpler we also slim down the props declaration to just an array.

Example

FoodItem.vue:

<template>
  <div>
    <h2>
      {{ foodName }}
      <img src="/img_quality.svg" v-show="foodIsFavorite">
    </h2>
    <p>{{ foodDesc }}</p>
    <button v-on:click="toggleFavorite">Favorite</button>
  </div>
</template>

<script>
  export default {
  props: ['foodName','foodDesc','isFavorite'],
  data() {
    return {
      foodIsFavorite: this.isFavorite
    }
  },
  methods: {
    toggleFavorite() {
      this.foodIsFavorite = !this.foodIsFavorite;
    }
  }
}
</script>

<style>
  img {
    height: 1.5em;
    float: right;
  }
</style>
Run Example »

Vue Exercises

Test Yourself With Exercises

Exercise:

What must we write in a component so that it receives data sent via the 'fish-name' attribute from App.vue as a prop?

<script>
  export default {
    : [
      ''
    ]
  }
</script>

Start the Exercise



Copyright 1999-2023 by Refsnes Data. All Rights Reserved.