---
title: "DatePicker"
description: "An internationalized date picker component."
canonical_url: "https://nuxt.mhaibaraai.cn/en/docs/components/date-picker"
---
# DatePicker

> An internationalized date picker component.

## Introduction

`MDatePicker` is an internationalized date picker built on `@internationalized/date` for timezone and locale handling. It supports single date, date range, and multiple date selection, with button trigger, clearable, and quick preset interactions.

> [!NOTE]
> See: https://ui.nuxt.com/docs/components/calendar
> 
> Built on Nuxt UI's Calendar component

> [!NOTE]
> See: https://react-spectrum.adobe.com/internationalized/date/index.html
> 
> Uses the 
> 
> @internationalized/date
> 
>  library for date handling, ensuring timezone safety and i18n support.

## Usage

The default button trigger displays the current date. Click to open the calendar panel and write the selected date to v-model:

```vue
<script setup lang="ts">
const value = ref("")
</script>

<template>
  <MDatePicker />
</template>
```

### `range` Date Range

`range` mode maintains `start` / `end` dates. `numberOfMonths` can display a dual-month calendar simultaneously:

```vue
<script setup lang="ts">
const value = ref("")
</script>

<template>
  <MDatePicker range :number-of-months="2" />
</template>
```

### `numberOfMonths` Number of Months

`numberOfMonths` controls the number of months displayed side by side in the popover, making cross-month selection easier:

```vue
<template>
  <MDatePicker :number-of-months="3" />
</template>
```

### `clearable` Clearable

`clearable` shows a clear entry when a value is set. Clicking it resets without opening the calendar:

```vue
<template>
  <MDatePicker clearable />
</template>
```

### `presets` Quick Presets

Setting `presets` to `default` automatically generates quick items like "Today", "This Week", "This Month" based on the current mode:

```vue
<template>
  <MDatePicker range presets="default" />
</template>
```

### `multiple` Multiple Date Selection

`multiple` mode saves multiple dates in an array. The button label can dynamically display the number of selected dates:

```vue
<template>
  <MDatePicker multiple :button-props='{"label":"Select multiple dates","color":"primary"}' />
</template>
```

### `buttonProps` Trigger Button

`buttonProps` is passed to the trigger button, allowing adjustment of label, color, variant, and icon:

```vue
<template>
  <MDatePicker :button-props='{"label":"Select birthday","color":"primary","variant":"outline","icon":"i-lucide-cake"}' />
</template>
```

## Examples

### Inheriting Field Context

When placed inside `UFormField`, it inherits `size` and error state, and the trigger button renders according to the form state:

```vue
<template>
  <UFormField label="Appointment Date" size="xs" error="Example error state">
    <MDatePicker />
  </UFormField>
</template>
```

### Inside `UFieldGroup`

When placed alongside a button inside `UFieldGroup`, they share size and border connection — ideal for filter bars with shortcut actions:

```vue
<template>
  <UFieldGroup size="xs">
    <MDatePicker />
    <UButton icon="i-lucide-calendar-check" color="neutral" variant="subtle" />
  </UFieldGroup>
</template>
```

### Constraining Selectable Date Boundaries

`minValue` and `maxValue` disable dates outside the boundary, restricting selection to future or past dates respectively:

```vue [ComponentsDatePickerValidationExample.vue]
<script setup lang="ts">
import type { CalendarDate } from '#movk/types'

const formatter = useDateFormatter()
const futureDate = shallowRef<CalendarDate>()
const pastDate = shallowRef<CalendarDate>()
</script>

<template>
  <div class="space-y-4">
    <UFormField label="未来日期">
      <MDatePicker
        v-model="futureDate"
        :min-value="formatter.getToday()"
        :button-props="{ label: '选择未来日期', class: 'w-full' }"
      />
    </UFormField>

    <UFormField label="过去日期">
      <MDatePicker
        v-model="pastDate"
        :max-value="formatter.getToday()"
        :button-props="{ label: '选择过去日期', class: 'w-full' }"
      />
    </UFormField>
  </div>
</template>
```

### Disabling Dates by Rule

`isDateUnavailable` disables dates according to business rules (e.g., weekends as shown in the example):

```vue [ComponentsDatePickerUnavailableExample.vue]
<script setup lang="ts">
import { CalendarDate } from '#movk/composables/useDateFormatter'
import type { DateValue } from '#movk/types'

const formatter = useDateFormatter()
const date = shallowRef(new CalendarDate(2025, 11, 18))

// 禁用周末
const isDateUnavailable = (date: DateValue) => {
  return formatter.isWeekend(date)
}
</script>

<template>
  <MDatePicker
    v-model="date"
    :is-date-unavailable="isDateUnavailable"
    :button-props="{ label: '仅工作日', class: 'w-full' }"
  />
</template>
```

### Custom Trigger Button Label

`labelFormat` receives formatting utilities and the current value to combine date and weekday info into the button label:

```vue [ComponentsDatePickerFormatExample.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const isoDate = shallowRef(new CalendarDate(2025, 11, 18))
const timestampDate = shallowRef(new CalendarDate(2025, 11, 18))
const customDate = shallowRef(new CalendarDate(2025, 11, 18))
</script>

<template>
  <div class="space-y-4">
    <UFormField label="ISO 格式">
      <MDatePicker v-model="isoDate" label-format="iso" :button-props="{ class: 'w-full' }" />
    </UFormField>

    <UFormField label="时间戳">
      <MDatePicker v-model="timestampDate" label-format="timestamp" :button-props="{ class: 'w-full' }" />
    </UFormField>

    <UFormField label="自定义">
      <MDatePicker
        v-model="customDate"
        :button-props="{ class: 'w-full' }"
        :label-format="(fmt, value) => {
          if (!value || !fmt.isDateValue(value)) return '选择日期'
          return `${fmt.format(value)} (星期${fmt.getDayOfWeek(value)})`
        }"
      />
    </UFormField>
  </div>
</template>
```

### Custom Quick Presets

Passing an array to `presets` allows business-rule-based date returns. Each item's `value` is a function that receives a `formatter`:

```vue [ComponentsDatePickerPresetsExample.vue]
<script setup lang="ts">
import type { DateValue } from '@movk/nuxt'

const value = shallowRef<DateValue>()
</script>

<template>
  <MDatePicker
    v-model="value"
    placeholder="选择日期"
    :presets="[
      { label: '本周一', value: f => f.getStartOfWeek(f.getToday()) as DateValue },
      { label: '本月初', value: f => f.getStartOfMonth(f.getToday()) as DateValue },
      { label: '本年初', value: f => f.getStartOfYear(f.getToday()) as DateValue }
    ]"
  />
</template>
```

## API

### Props

```ts
/**
 * Props for the MDatePicker component
 */
interface MDatePickerProps {
  id?: string | undefined;
  name?: string | undefined;
  /**
   * @default '选择日期'
   */
  placeholder?: string | undefined;
  buttonProps?: ButtonProps | undefined;
  popoverProps?: PopoverProps<P> | undefined;
  /**
   * @default 'formatted'
   */
  labelFormat?: "iso" | "timestamp" | "unix" | "date" | "formatted" | (formatter: { format: (date: DateValue | null | undefined) => string; formatRange: (start: DateValue | null | undefined, end: DateValue | null | undefined, separator?: string) => string; ... 38 more ...; timeZone: string; }, modelValue: CalendarModelValue<...> | undefined): string | undefined;
  /**
   * v-model 投影输出格式
   * @default 'date-value'
   */
  valueFormat?: V | undefined;
  clearable?: boolean | undefined;
  /**
   * 快捷预设
   */
  presets?: "default" | DatePickerPreset<R, M>[] | undefined;
  ui?: Record<string, C> & { content?: SlotClass; arrow?: SlotClass; wrapper?: SlotClass; presets?: SlotClass; presetButton?: SlotClass; calendar?: SlotClass; clearIcon?: SlotClass; } | undefined;
  /**
   * 语言区域
   * @default 'zh-CN'
   */
  locale?: string | undefined;
  /**
   * 日期格式化选项
   */
  formatOptions?: Intl.DateTimeFormatOptions | undefined;
  /**
   * 时区标识符,默认使用本地时区
   */
  timeZone?: string | undefined;
  /**
   * The element or component this component should render as.
   * @default 'div'
   */
  as?: any;
  /**
   * The type of picker.
   * - `date` renders a day calendar whose heading can switch to a month then year view.
   * - `month` renders a standalone month picker.
   * - `year` renders a standalone year picker.
   * @default 'date'
   */
  type?: "date" | "month" | "year" | undefined;
  /**
   * The icon to use for the next year control.
   * @default appConfig.ui.icons.chevronDoubleRight
   */
  nextYearIcon?: any;
  /**
   * Configure the next year button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  nextYear?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the next month control.
   * @default appConfig.ui.icons.chevronRight
   */
  nextMonthIcon?: any;
  /**
   * Configure the next month button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  nextMonth?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the previous year control.
   * @default appConfig.ui.icons.chevronDoubleLeft
   */
  prevYearIcon?: any;
  /**
   * Configure the prev year button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  prevYear?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the previous month control.
   * @default appConfig.ui.icons.chevronLeft
   */
  prevMonthIcon?: any;
  /**
   * Configure the prev month button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  prevMonth?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * Whether to make the heading a button that switches between the day, month and year views.
   * Has no effect when `type` is `year`. Can be an object to override the button props.
   * `{ color: 'neutral', variant: 'ghost', block: true }`{lang="ts-type"}
   * @default true
   */
  viewControl?: boolean | Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * @default 'primary'
   */
  color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "important" | "neutral" | undefined;
  /**
   * @default 'solid'
   */
  variant?: "solid" | "outline" | "soft" | "subtle" | undefined;
  /**
   * @default 'md'
   */
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
  /**
   * Whether or not a range of dates can be selected
   */
  range?: R | undefined;
  /**
   * Whether or not multiple dates can be selected
   */
  multiple?: M | undefined;
  /**
   * Show month controls
   */
  monthControls?: boolean | undefined;
  /**
   * Show year controls
   */
  yearControls?: boolean | undefined;
  defaultValue?: CalendarDefaultValue<R, M> | undefined;
  weekNumbers?: boolean | undefined;
  /**
   * The default placeholder date
   */
  defaultPlaceholder?: CalendarDate | CalendarDateTime | ZonedDateTime | undefined;
  /**
   * When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected.
   */
  allowNonContiguousRanges?: boolean | undefined;
  /**
   * This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month
   */
  pagedNavigation?: boolean | undefined;
  /**
   * Whether or not to prevent the user from deselecting a date without selecting another date first
   */
  preventDeselect?: boolean | undefined;
  /**
   * The maximum number of days that can be selected in a range
   */
  maximumDays?: number | undefined;
  /**
   * The day of the week to start the calendar on
   */
  weekStartsOn?: 0 | 1 | 2 | 4 | 5 | 3 | 6 | undefined;
  /**
   * The format to use for the weekday strings provided via the weekdays slot prop
   */
  weekdayFormat?: "narrow" | "short" | "long" | undefined;
  /**
   * Whether or not to always display 6 weeks in the calendar
   */
  fixedWeeks?: boolean | undefined;
  /**
   * The maximum date that can be selected
   */
  maxValue?: CalendarDate | CalendarDateTime | ZonedDateTime | undefined;
  /**
   * The minimum date that can be selected
   */
  minValue?: CalendarDate | CalendarDateTime | ZonedDateTime | undefined;
  /**
   * The number of months to display at once
   */
  numberOfMonths?: number | undefined;
  /**
   * Whether or not the calendar is disabled
   */
  disabled?: boolean | undefined;
  /**
   * Whether or not the calendar is readonly
   */
  readonly?: boolean | undefined;
  /**
   * If true, the calendar will focus the selected day, today, or the first day of the month depending on what is visible when the calendar is mounted
   */
  initialFocus?: boolean | undefined;
  /**
   * A function that returns whether or not a date is disabled
   */
  isDateDisabled?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns whether or not a date is unavailable
   */
  isDateUnavailable?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns whether or not a date is hightable
   */
  isDateHighlightable?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component.
   */
  nextPage?: (placeholder: DateValue): DateValue | undefined;
  /**
   * A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component.
   */
  prevPage?: (placeholder: DateValue): DateValue | undefined;
  /**
   * Whether or not to disable days outside the current view.
   */
  disableDaysOutsideCurrentView?: boolean | undefined;
  /**
   * Which part of the range should be fixed
   */
  fixedDate?: "start" | "end" | undefined;
  /**
   * A function that returns whether or not a month is disabled
   */
  isMonthDisabled?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns whether or not a month is unavailable
   */
  isMonthUnavailable?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns whether or not a year is disabled
   */
  isYearDisabled?: (date: DateValue): boolean | undefined;
  /**
   * A function that returns whether or not a year is unavailable
   */
  isYearUnavailable?: (date: DateValue): boolean | undefined;
  modelValue?: FormattedValue<R, M, V> | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MDatePicker component
 */
interface MDatePickerEmits {
  update:modelValue: (payload: [value: FormattedValue<R, M, V>]) => void;
  update:placeholder: (payload: [date: DateValue]) => void;
  update:validModelValue: (payload: [date: DateRange]) => void;
  update:startValue: (payload: [date: DateValue | undefined]) => void;
  close:prevent: (payload: []) => void;
  update:open: (payload: [value: boolean]) => void;
  update:modelValue: (payload: [value: FormattedValue<R, M, V> | undefined]) => void;
}
```

### Slots

```ts
/**
 * Slots for the MDatePicker component
 */
interface MDatePickerSlots {
  default(): any;
  content(): any;
  heading(): any;
  day(): any;
  week-day(): any;
  month-cell(): any;
  year-cell(): any;
  leading(): any;
  trailing(): any;
}
```

## Theme

<component-theme>



</component-theme>

## Changelog

See commit history for [src/runtime/components/DatePicker.vue](https://github.com/mhaibaraai/movk-nuxt/commits/main/src/runtime/components/DatePicker.vue).


## Sitemap

See the full [sitemap](https://nuxt.mhaibaraai.cn/sitemap.md) for all pages.
