Sometimes, we want to build our own date picker component in our Vue 3 app to let users select a date.
In this article, we’ll look at how to build a date picker component with Vue 3.
Build a Datepicker Component with Vue.js 3
We can build our own input component by creating a component that takes the modelValue
prop and emits the update:modelValue
event.
The 2 things together is the same as the v-model
directive.
So we can write the following code to create a date picker and use it.
App.vue
<template>
<DatePicker v-model="date" />
<p>{{ date }}</p>
</template>
<script>
import DatePicker from "./components/DatePicker.vue";
export default {
name: "App",
components: {
DatePicker,
},
data() {
return {
date: new Date(2020, 1, 1),
};
},
};
</script>
components/DatePicker.vue
<template>
<div id="date-picker">
<div>
<label>year</label>
<br />
<select v-model="year">
<option v-for="y in years" :key="y">
{{ y }}
</option>
</select>
</div>
<div>
<label>month</label>
<br />
<select v-model="month">
<option v-for="m in 12" :key="m" :value="m - 1">
{{ m }}
</option>
</select>
</div>
<div>
<label>day</label>
<br />
<select v-model="day">
<option v-for="d in maxDate" :key="d">
{{ d }}
</option>
</select>
</div>
</div>
</template>
<style scoped>
#date-picker {
display: flex;
}
#date-picker div {
margin-right: 10px;
}
</style>
<script>
import moment from "moment";
export default {
name: "DatePicker",
props: {
modelValue: Date,
},
data() {
return {
years: [],
year: new Date().getFullYear(),
month: 0,
day: 1,
};
},
methods: {
emitDate() {
const { year, month, day } = this;
this.$emit("update:modelValue", new Date(year, month, day).toString());
},
},
watch: {
year() {
this.emitDate();
},
month() {
this.emitDate();
},
day() {
this.emitDate();
},
},
computed: {
maxDate() {
const { month } = this;
if ([0, 2, 4, 6, 7, 9, 11].includes(month)) {
return 31;
} else if ([3, 5, 8, 10].includes(month)) {
return 30;
}
return 28;
},
},
beforeMount() {
const currentYear = new Date().getFullYear();
for (let i = -100; i <= 100; i++) {
this.years.push(currentYear + i);
}
const d = moment(this.modelValue);
this.year = +d.format("YYYY");
this.month = +d.format("MM") - 1;
this.day = +d.format("DD");
},
};
</script>
In App.vue
, we add the DatePicker
component and bind it to a date string with v-model
.
We create the date string with the Date
constructor.
It’ll be converted to a string automatically when we get it from the modelValue
prop.
Below that, we show the date
value.
Then in DatePicker.vue
, we add the 3 select elements to let us pick the year, month, and day.
We bind the select
element value to reactive properties with v-model
.
The value
for the month
starts with 0 and ends with 11 to match what the Date
constructor accepts.
We use v-for
to render the numbers for the value for the options.
Next, we add some styles to the style
tag to make the dropdowns display side by side and add margins between them.
Then we have the component object.
The component takes the modelValue
prop which is a string.
data
returns the reactive properties we use for the template.
years
is an array of years for the year dropdown which we’ll populate later.
year
, month
, and day
are set to default values.
Next, we have the emitDate
method to emit the update:modelValue
event with the date string.
We call it in the year
, month
, and day
watchers so it’ll run when any of these values change.
Then we add the maxDate
computed property to return the max day we can set according to which month is chosen.
Since JavaScript Date
constructor takes months that are 0 based, we check month values from 0 to 11, where 0 is January and 11 is December.
Finally, in the beforeMount
hook, we populate the years
array with 100 years before and after the current year.
And we get the modelValue
prop’s value and parse the year, month, and day values
We do the parsing with the format
method that comes with moment objects.
Now when we change the options in the drop-down, we should see the choices reflect in the text below.
Conclusion
We can create a drop-down component easily with Vue 3.