Calendar

Mini-program developers can use the Calendar component to allow users to view and interact with dates based on the calendar form. This topic covers the user experience, attribute details, and sample code for the Calendar component.

User experience

The following image shows a calendar with the default UI copy:

image.png

Attributes

Attribute

Data type

Default

Description

defaultValue

CalendarValue

N/A

The preselected date or date range when the calendar is first displayed.

value

CalendarValue

N/A

The date or date range that is currently selected.

selectionMode

String

range

The type of date selection available to users. Valid values are:

  • single: Allow users to select a single day.
  • range: Allow users to select a start and end day to define a date range.

monthRange

[Number,Number]

current month and next two months

The months displayed on the calendar.

weekStartsOn

String

Sunday

The first day of the week. Valid values are:

  • Sunday: The week starts on Sunday.
  • Monday: The week starts on Monday.

localeText

Partial<LocaleText>

See LocaleText for details.

The localized UI copy for calendar display, such as the names for the months and the days of the week.

Note: The default copy is in Chinese. Specify this attribute to display text in another language.

changedScrollIntoView

Boolean

N/A

Whether to scroll the view when the selected date is changed.

onChange

(date: CalendarValue) => void

N/A

The callback function that is triggered when the selected date is changed.

onFormatter

(cell: CellState, currentValue: CalendarValue) => CellState

N/A

The customized display and data for individual date cells.

CalendarValue

CalendarValue represents the format of the selected dates on the calendar. It takes either of the following two forms:

  • Number: A number that specifies a single day. The value is a timestamp that is accurate to the millisecond.
  • [Number,Number]: An array of two numbers that specify the start and end dates of a continuous date range. Each number is a timestamp that is accurate to the millisecond.

CellState

CellState provides the state of date cells and is defined as:

copy
interface CellState {
    /**
   * Whether the date cell is disabled.
   */
    disabled: boolean;
    /**
   * The content that is displayed at the top of the date cell.
   */
    top?: { label: string; className?: string };
    /**
   * The content that is displayed at the top of the date cell.
   */
    bottom?: { label: string; className?: string };
    /**
   * The timestamp.
   */
    time: number;
    /**
   * The date.
   */
    date: number;
    /**
   * Whether the date cell is selected.
   */
    isSelected: boolean;
}

LocaleText

LocaleText provides the localized UI copy and is defined as:

copy
interface LocaleText {
  /**
   * The names of the days of the week from Monday to Sunday.
   * The default value is ['一', '二', '三', '四', '五', '六', '日'].
   */
  weekdayNames: string[];
  /**
   * The names of the months. The default value is in 'YYYY年MM月' format.
   */
  title: string;
  /**
   * Text for the current date on the cell. The default value is '今日'.
   */
  today: string;
  /**
   * Text for the start date. The default value is '开始'.
   */
  start: string;
  /**
   * Text for the end date. The dedault value is '结束'.
   */
  end: string;
  /**
   * Text for same-day start and end. The default value is '开始/结束'.
   */
  startAndEnd: string;
}

Sample code

The following sample code shows how to create different calendars:

.axml

copy
<ant-container
  title="Default: Selection of a date range and display of 3 months beginning from the current month">
  <view
    slot="content"
    style="height: 1000rpx">
    <ant-calendar defaultValue="{{ demo1.defaultValue }}" />
  </view>
</ant-container>

<ant-container
  title="Selection of a single day">
  <view
    slot="content"
    style="height: 1000rpx">
    <ant-calendar
      selectionMode="single"
      defaultValue="{{ demo2.defaultValue }}" />
  </view>
</ant-container>

<ant-container
  title="Customize the top of the calendar">
  <view slot="content">
    <view class="custom-header">
      <view
        onTap="demo3PreviousMonth"
        class="custom-header-left">
        <ant-icon type="LeftOutline" />
        Previous
      </view>
      <view>{{ demo3.title }}</view>
      <view
        onTap="demo3NextMonth"
        class="custom-header-right">
        Next
        <ant-icon type="RightOutline" />
      </view>
    </view>
    <ant-calendar monthRange="{{ demo3.monthRange }}">
      <view slot="calendarTitle" />
    </ant-calendar>
  </view>
</ant-container>

<ant-container
  title="Customize date cells">
  <view slot="content">
    <ant-calendar
      monthRange="{{ demo8.monthRange }}"
      onFormatter="{{ demo8Formatter ? demo8Formatter : 'demo8Formatter' }}" />
  </view>
</ant-container>

<ant-container
  title="Dynamic control, choose an end date within the following 3 days">
  <view slot="content">
    <ant-calendar
      onFormatter="{{ demoFormatter ? demoFormatter : 'demoFormatter' }}" />
  </view>
</ant-container>

<ant-container
  title="Set Monday as the first day of the week">
  <view
    slot="content"
    style="height: 1000rpx">
    <ant-calendar weekStartsOn="Monday" />
  </view>
</ant-container>

<ant-container
  title="Localize UI copy">
  <view slot="content">
    <ant-calendar
      monthRange="{{ demo7.monthRange }}"
      localeText="{{ demo7.localeText }}" />
  </view>
</ant-container>

<ant-container
  title="Control mode">
  <view slot="content">
    <ant-calendar
      value="{{ demo9.value }}"
      monthRange="{{ demo9.monthRange }}"
      onChange="demo9HandleChange"
      selectionMode="single" />
    <ant-button
      type="primary"
      onTap="demo9HandlePreviousDay">
      Previous
    </ant-button>
    <ant-button
      style="margin-top: 8rpx"
      type="primary"
      onTap="demo9HandleNextDay">
      Next
    </ant-button>
  </view>
</ant-container>

.js

copy
import dayjs from 'dayjs';
const localeText = {
  weekdayNames: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
  title: 'YYYY/MM',
  today: 'Today',
  start: 'Start',
  end: 'End',
  startAndEnd: 'Start/End',
};
function demo8Formatter(cell) {
  const isOdd = dayjs(cell.time).date() % 2 === 1;
  const isNotBeginEnd = !cell.isSelectedBegin && !cell.isSelectedEnd;
  const isWeekend = dayjs(cell.time).day() > 4;
  let topClassName;
  if (isNotBeginEnd) {
    topClassName = isOdd ? 'odd' : 'even';
  }
  return {
    top: {
      className: topClassName,
      label: isOdd ? 'Odd' : 'Even',
    },
    bottom: {
      label: isWeekend ? 'Weekend' : '',
    },
  };
}
function demoFormatter(cell, value) {
  if (Array.isArray(value) && value.length == 1) {
    const current = value[0];
    return {
      disabled: dayjs(cell.time).diff(dayjs(current), 'days') > 3,
      bottom: dayjs(cell.time).diff(dayjs(current), 'days') > 3
        ? {
          label: 'Unselectable',
        }
        : undefined,
    };
  }
  return {};
}
Page({
  data: {
    demo1: {
      defaultValue: [Date.now(), Date.now()],
      visible: true,
    },
    demo2: {
      defaultValue: Date.now(),
      visible: true,
    },
    demo3: {
      title: dayjs(new Date().getTime()).format('YYYY年MM月'),
      monthRange: [new Date().getTime(), new Date().getTime()],
      visible: true,
    },
    demo7: {
      localeText,
      visible: true,
      monthRange: [new Date().getTime(), new Date().getTime()],
    },
    demo8: {
      visible: true,
      monthRange: [new Date().getTime(), new Date().getTime()],
    },
    demo9: {
      visible: true,
      value: Date.now(),
      monthRange: [new Date().getTime(), new Date().getTime()],
    },
  },
  demo3NextMonth() {
    const current = this.data.demo3.monthRange[0];
    const newMonth = dayjs(current).add(1, 'month').toDate().getTime();
    this.setData({
      'demo3.title': dayjs(newMonth).format('YYYY年MM月'),
      'demo3.monthRange': [newMonth, newMonth],
    });
  },
  demo3PreviousMonth() {
    const current = this.data.demo3.monthRange[0];
    const newMonth = dayjs(current).add(-1, 'month').toDate().getTime();
    this.setData({
      'demo3.title': dayjs(newMonth).format('YYYY年MM月'),
      'demo3.monthRange': [newMonth, newMonth],
    });
  },
  demoFormatter,
  demo8Formatter,
  demo9HandleChange(value) {
    this.setData({
      'demo9.value': value,
    });
    },
    demo9HandlePreviousDay() {
        this.setData({
            'demo9.value': this.data.demo9.value - 1000 * 24 * 3600,
        });
    },
    demo9HandleNextDay() {
        this.setData({
            'demo9.value': this.data.demo9.value + 1000 * 24 * 3600,
        });
    },
});

.acss

copy
page {
  padding: 8px;
  box-sizing: border-box;
}
.custom-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 60rpx;
}
.custom-header-left {
  display: flex;
  align-items: center;
}
.custom-header-right {
  display: flex;
  align-items: center;
}
.odd {
  color: red;
}
.even {
  color: blue;
}

.json

copy
{
  "defaultTitle": "Calendar",
  "usingComponents": {
    "ant-icon": "antd-mini/es/Icon/index",
    "ant-button": "antd-mini/es/Button/index",
    "ant-calendar": "antd-mini/es/Calendar/index",
    "ant-container": "antd-mini/es/Container/index"
  }
}

FAQs

How do I set a default date range selection on the calendar?

To set a default date range, specify the start and end dates using defaultValue. For example, to set the start date to today and the end date to seven days later, use the following code:

copy
defaultValue=[dayjs().startOf('date'), dayjs().add(7, 'days').startOf('date')];

How do I use onFormatter to customize date cell data?

The onFormatter function is used to customize the state and value of each date cell. For example, to make dates before today unselectable, take the following steps:

  1. Link to the method in the AXML file:
copy
<calendar onFormatter="handleFormat" />
  1. Define the method in the JS file:
copy
import dayjs from 'dayjs';

Page({
  handleFormat(cell: CellState) {
    // Make dates before today unselectable
    return {
      disabled: dayjs(cell.time).isBefore(dayjs().startOf('date')),
    };
  },
});