Components

Date input

Use the date input component to help users enter a memorable date or one they can easily look up.

See the GOV.UK Design System documentation on date inputs for more information on when to use this component.

Form binding with v-model

You can bind data to the individual day, month and year fields using v-model:day, v-model:month and v-model:year.

You should bind these as strings, not numbers. Users can type any characters in the inputs, so you'll need to validate whether the individual parts are numbers and whether the whole thing is a valid date, for example by using Date.parse().

When was your passport issued?

For example, 27 3 2007
You haven't entered a full date yet
<script setup lang="ts">
import { ref, computed } from 'vue'

const day = ref('')
const month = ref('')
const year = ref('')

const formattedDate = computed(() => {
  const parsedDate = Date.parse(`${year.value}-${month.value}-${day.value}`)

  if(!isNaN(parsedDate)) {
    const date = new Date(parsedDate)
    return date.toLocaleString('en-GB', { dateStyle: 'full' })
  }
})
</script>

<template>
  <gv-date-input
    legend="When was your passport issued?"
    :legend-is-page-heading="true"
    legend-class="govuk-fieldset__legend--l"
    hint="For example, 27 3 2007"
    v-model:day="day"
    v-model:month="month"
    v-model:year="year"
  />
  
  <gv-inset-text aria-live="polite">
    <template v-if="formattedDate">
      Your passport was issued on {{ formattedDate }}
    </template>
    <template v-else>
      You haven't entered a full date yet
    </template>
  </gv-inset-text>
</template>

Use the autocomplete prop for a date of birth

Set the autocomplete prop to bday if you're asking the user for their date of birth. This will automatically set the autocomplete attribute to bday-day, bday-month and bday-year on the text inputs in this component.

What is your date of birth?
For example, 31 3 1980
You haven't entered a full date yet
<script setup lang="ts">
import { ref, computed } from 'vue'

const day = ref('')
const month = ref('')
const year = ref('')

const formattedDate = computed(() => {
  const parsedDate = Date.parse(`${year.value}-${month.value}-${day.value}`)

  if(!isNaN(parsedDate)) {
    const date = new Date(parsedDate)
    return date.toLocaleString('en-GB', { weekday: 'long' })
  }
})
</script>

<template>
  <gv-date-input
    legend="What is your date of birth?"
    hint="For example, 31 3 1980"
    autocomplete="bday"
    v-model:day="day"
    v-model:month="month"
    v-model:year="year"
  />
  
  <gv-inset-text aria-live="polite">
    <template v-if="formattedDate">
      You were born on a {{ formattedDate }}
    </template>
    <template v-else>
      You haven't entered a full date yet
    </template>
  </gv-inset-text>
</template>

Validation and error messages

Set day-has-error, month-has-error or year-has-error to true to highlight specific input fields, and error-message to set the error message for the whole component.

See the GOV.UK Design System guidance on error messages for date inputs for more details on how to validate dates.

The example below shows a basic date validator which follows these guidelines.

When was your passport issued?

For example, 27 3 2007
<script setup lang="ts">
import { ref } from 'vue'

const day = ref('19')
const month = ref('3')
const year = ref('2100')

const dayHasError = ref(false)
const monthHasError = ref(false)
const yearHasError = ref(false)
const errorMessage = ref('')

function validateDate() {
  dayHasError.value = false;
  monthHasError.value = false;
  yearHasError.value = false;
  errorMessage.value = '';
  
  const hasDay = day.value.length > 0 && !isNaN(parseInt(day.value))
  const hasMonth = month.value.length > 0 && !isNaN(parseInt(month.value))
  const hasYear = year.value.length > 0 && !isNaN(parseInt(year.value))
  
  // Check if every field is empty
  if(!hasDay && !hasMonth && !hasYear) {
    errorMessage.value = 'Enter the date your passport was issued'
    dayHasError.value = true
    monthHasError.value = true
    yearHasError.value = true
    return
  }
  
  // Check if any individual fields are empty
  if(!hasDay || !hasMonth || !hasYear) {
    const missingFields = [];
    
    if(!hasDay) {
      missingFields.push('day')
      dayHasError.value = true;
    }
    
    if(!hasMonth) {
      missingFields.push('month')
      monthHasError.value = true;
    }
    
    if(!hasYear) {
      missingFields.push('year')
      yearHasError.value = true;
    }
    
    errorMessage.value = `The date your passport was issued must include a ${missingFields.join(' and ')}`
    return
  }
  
  // Check day, month or year are obviously invalid
  if(parseInt(day.value) < 1 || parseInt(day.value) > 31) {
    dayHasError.value = true
  }

  if(parseInt(month.value) < 1 || parseInt(month.value) > 12) {
    monthHasError.value = true
  }

  if(parseInt(year.value) < 1900 || parseInt(year.value) > 2100) {
    yearHasError.value = true
  }

  // Check if whole date is valid  (eg 31-2-2023 would pass previous checks but fail here)
  const parsedDate = Date.parse(`${year.value}-${month.value}-${day.value}`)
  
  if(isNaN(parsedDate)) {
    dayHasError.value = true
    monthHasError.value = true
    yearHasError.value = true
  }
  
  if(dayHasError.value || monthHasError.value || yearHasError.value) {
    errorMessage.value = `The date your passport was issued must be a real date`
    return;
  }
  
  // Check if date is in the past (today is OK)
  if(new Date(parsedDate) > new Date()) {
    dayHasError.value = true
    monthHasError.value = true
    yearHasError.value = true
    errorMessage.value = `The date your passport was issued must be today or in the past `
    return;
  }
  
  alert('The date is valid')
}
</script>

<template>
  <gv-date-input
    legend="When was your passport issued?"
    :legend-is-page-heading="true"
    legend-class="govuk-fieldset__legend--l"
    hint="For example, 27 3 2007"
    v-model:day="day"
    v-model:month="month"
    v-model:year="year"
    :day-has-error="dayHasError"
    :month-has-error="monthHasError"
    :year-has-error="yearHasError"
    :error-message="errorMessage"
  />
  
  <gv-button @click="validateDate">Validate date</gv-button>
</template>

Props

NameTypeDescription
day string
The value of the day input. In most cases you should use v-model:day instead of setting this prop directly.
month string
The value of the month input. In most cases you should use v-model:month instead of setting this prop directly.
year string
The value of the year input. In most cases you should use v-model:year instead of setting this prop directly.
dayHasError boolean
If true, the day input will be outlined in red
monthHasError boolean
If true, the month input will be outlined in red
yearHasError boolean
If true, the year input will be outlined in red
autocomplete string
The type of autocomplete to allow on the inputs. Currently only allows birthday.

Allowed values: bday.
id string
An ID for the date component. This will be used as a prefix for the IDs of the individual inputs. If you don't provide an ID, one will be generated automatically.
namePrefix string
An optional prefix for the name attribute on the individual inputs. If provided, these attributes will be set to [prefix]-day, [prefix]-month and [prefix]-year. If not provided, the names will be day, month, and year.
formGroupClass string|array|object
Classes to add to the form group. You can bind a string, an array or an object, as with normal Vue class bindings.
fieldsetDescribedBy string
One or more element IDs to add to the aria-describedby attribute, used to provide additional descriptive information for screenreader users.
fieldsetClass string|array|object
Classes to add to the fieldset container. You can bind a string, an array or an object, as with normal Vue class bindings.
fieldsetRole string
Optional ARIA role attribute to add to the fieldset container.
legend string
Text to use within the legend. If content is provided in the legend slot, this prop will be ignored.
legendClass string|array|object
Classes to add to the legend. You can bind a string, an array or an object, as with normal Vue class bindings.
legendIsPageHeading boolean
Whether the legend also acts as the heading for the page.
hint string
Text to use within the hint. If content is provided in the hint slot, this prop will be ignored.
hintClass string|array|object
Classes to add to the hint span tag. You can bind a string, an array or an object, as with normal Vue class bindings.
errorMessage string
Text to use within the error message. If content is provided in the error-message slot, this prop will be ignored.
errorMessageClass string|array|object
Classes to add to the error message <p> tag. You can bind a string, an array or an object, as with normal Vue class bindings.
errorMessageVisuallyHiddenText string
A visually hidden prefix used before the error message. Defaults to 'Error'.

Slots

NameDescription
legend
The content of the legend. If content is provided in this slot, the legend prop will be ignored.
hint
The content of the hint. If content is provided in this slot, the hint prop will be ignored.
error-message
The content of the error message. If content is provided in this slot, the errorMessage prop will be ignored.