Props & Dynamic Styles

vue.js logo

Passing data to components via props

Our project currently repeats the Event.vue component for each event we have stored. This will repeat the same event for each of the six array items in the browser. The reason each event is the same is because this is the HTML we have set up in the Event.vue component:

<template>
    <article>
        <div class="event_data">
            <h3 class="event_name">Graduation</h3>
            <p class="event_details">Party time!!!</p>
        </div>
        <div class="event_countdown">
            <div class="remove_btn_wrapper">
                <button class="remove_btn">&#10060;</button>
            </div>
            <div>
                <p class="days_left">56</p>
                <small>days left</small>
            </div>
        </div>
    </article>
</template>

We can pass the correct data from each event to the component using props.

Props are Vue's way of passing data from parent to child components. They create a one-way data flow where parent components can send data down to their children, but children can not directly modify the data they receive. In the App.vue, pass in the name and details props as attributes to the <Event>:

<Event
    v-for="event in eventData"
    :key="event.id"
    :name="event.name"
    :details="event.details"
/>
  • : is shorthand for v-bind, telling Vue to evaluate the expression as JavaScript.
  • :name binds the event's name to a prop called name in the child component.
  • :details binds the event's details to a prop called details in the child component.
  • The right side (event.name, event.details) references data from our v-for loop.
  • Without the colon, Vue would treat event.name as a literal string instead of a JavaScript expression.

Defining props in a component

We then need to declare which props are to be received in the component using defineProps(), add this to the Event.vue:

<script setup>
defineProps({
    name: {
        type: String,
        required: true,
    },
    details: {
        type: String,
        required: true,
    },
});
</script>

Using defineProps() allows for setting up validation and requirements:

  • type: The expected data type of the prop (String, Number, Boolean, Array, etc.).
  • required: Whether the prop must be provided.
  • default: A default/fallback value if no prop is received.
  • validator: A function to check if prop values are valid.

Rendering props in a template

These props are now available to use in the <template> section using interpolation ({{ }}). The current values always remain the same each time we use the component:

<template>
    <article>
        <div class="event_data">
            <h3 class="event_name">Graduation</h3>
            <p class="event_details">Party time!!!</p>

Update the event name and details with our dynamic props:

<template>
    <article>
        <div class="event_data">
            <h3 class="event_name">{{ name }}</h3>
            <p class="event_details">{{ details }}</p>

This double curly brace syntax is used to pass dynamic data to our HTML, similar to using a JavaScript variable. Both {{ name }} and {{ details }} will be replaced with the actual text of the prop passed to the component (Graduation, Holidays, etc).

Vue.js style bindings

The events also have a CSS background property available:

{
  id: 1,
  name: "Graduation",
  details: "wooohoo!!!",
  date: "2027-09-25",
  background: "linear-gradient(135deg, #FF416C, #FF4B2B)",
},

We can also pass this as a prop and use it to make the color of each event unique. In the App.vue, update the props to also pass the background:

<Event
  v-for="event in eventData"
  :key="event.id"
  :name="event.name"
  :details="event.details"
  :background="event.background"
/>

Add this to defineProps() in the Event component:

<script setup>
defineProps({
    name: {
        type: String,
        required: true,
    },
    details: {
        type: String,
        required: true,
    },
    background: {
        type: String,
        required: true,
    },
});
</script>

Then update the <article> to include the inline styles:

<template>
    <article :style="{ background }">
  • :style is a Vue's directive for binding inline styles with dynamic data. The binding accepts a JavaScript object.
  • { background } is shorthand for { background: background } when prop name matches CSS property.
  • Multiple styles can be added: :style="{ background, color: textColor, fontSize: '16px' }"
  • Vue automatically adds vendor prefixes when required.

With this update we can also remove the CSS background property:

<style scoped>
article {
    display: flex;
    align-items: center;
    /* background: linear-gradient(135deg, #2c3e50, #3498db); */