Date picker
A date field that opens a themed calendar and returns a plain YYYY-MM-DD string.
vue
<script setup lang="ts">
import SaDatePicker from '@shared/components/common/SaDatePicker.vue'
import { ref } from 'vue'
const date = ref('')
</script>
<template>
<div class="max-w-xs">
<SaDatePicker v-model="date" />
<p class="mt-2 text-sm text-muted-foreground">
{{ date === '' ? 'No date selected' : date }}
</p>
</div>
</template>Usage
Bind a string with v-model. An empty string means no date. The field shows the date in the app's language, and the calendar starts the week on the day that language uses: Sunday in English, Monday in most European languages, Saturday in Arabic.
SaDatePicker returns a local calendar date, not a timestamp, so a date picked late in the evening east of UTC stays the date the reader picked.
Examples
Clearable
clearable adds a Clear action inside the popover, which sets the model back to an empty string.
vue
<script setup lang="ts">
import SaDatePicker from '@shared/components/common/SaDatePicker.vue'
import { ref } from 'vue'
const date = ref('2026-09-24')
</script>
<template>
<div class="max-w-xs">
<SaDatePicker v-model="date" clearable />
</div>
</template>Invalid and disabled
invalid sets aria-invalid on the trigger, which draws the field in the destructive color. disabled blocks the popover.
vue
<script setup lang="ts">
import SaDatePicker from '@shared/components/common/SaDatePicker.vue'
import { Label } from '@shared/components/ui/label'
import { ref } from 'vue'
const invalid = ref('')
const locked = ref('2026-01-31')
</script>
<template>
<div class="flex max-w-md flex-col gap-4">
<div class="flex flex-col gap-1.5">
<Label for="due">Due date</Label>
<SaDatePicker id="due" v-model="invalid" invalid placeholder="Pick a due date" />
<p class="text-sm text-destructive">
A due date is required.
</p>
</div>
<SaDatePicker v-model="locked" disabled />
</div>
</template>API
Source: src/shared/components/common/SaDatePicker.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string | required | The date as YYYY-MM-DD, or an empty string for no date. |
id | string | — | Id on the trigger button, for a <Label for="...">. |
placeholder | string | 'common.pickADate' | Text shown when there is no date. A translation key, or plain text. |
disabled | boolean | false | Blocks the popover. |
invalid | boolean | false | Sets aria-invalid on the trigger. |
clearable | boolean | false | Adds a Clear action inside the popover. |
Emits
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: string | The picked date as YYYY-MM-DD, or an empty string after Clear. |
Slots
None.
Accessibility
- The trigger is a button. It opens the calendar on
EnterorSpace, andEscapecloses it and returns focus to the trigger. invalidsetsaria-invalid="true"on the trigger, so a screen reader announces the field as invalid. Pair it with your own message, as the example does.- The calendar is Reka UI's, so the arrow keys move between days and the focused day is announced with its full date.
- Give the field a visible label with
idand<Label for="...">; the component does not invent one.