Calendar
Container for displaying data in calendar form.
When To Use#
When data is in the form of dates, such as schedules, timetables, prices calendar, lunar calendar. This component also supports Year/Month switch.
Examples
2022
Feb
| Su | Mo | Tu | We | Th | Fr | Sa | 
|---|---|---|---|---|---|---|
30  | 31  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
13  | 14  | 15  | 16  | 17  | 18  | 19  | 
20  | 21  | 22  | 23  | 24  | 25  | 26  | 
27  | 28  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
import { Calendar } from 'antd';
function onPanelChange(value, mode) {
  console.log(value.format('YYYY-MM-DD'), mode);
}
ReactDOM.render(<Calendar onPanelChange={onPanelChange} />, mountNode);2022
Feb
| Su | Mo | Tu | We | Th | Fr | Sa | 
|---|---|---|---|---|---|---|
30  | 31  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08 
  | 09  | 10 
  | 11  | 12  | 
13  | 14  | 15 
  | 16  | 17  | 18  | 19  | 
20  | 21  | 22  | 23  | 24  | 25  | 26  | 
27  | 28  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08 
  | 09  | 10 
  | 11  | 12  | 
import { Calendar, Badge } from 'antd';
function getListData(value) {
  let listData;
  switch (value.date()) {
    case 8:
      listData = [
        { type: 'warning', content: 'This is warning event.' },
        { type: 'success', content: 'This is usual event.' },
      ];
      break;
    case 10:
      listData = [
        { type: 'warning', content: 'This is warning event.' },
        { type: 'success', content: 'This is usual event.' },
        { type: 'error', content: 'This is error event.' },
      ];
      break;
    case 15:
      listData = [
        { type: 'warning', content: 'This is warning event' },
        { type: 'success', content: 'This is very long usual event。。....' },
        { type: 'error', content: 'This is error event 1.' },
        { type: 'error', content: 'This is error event 2.' },
        { type: 'error', content: 'This is error event 3.' },
        { type: 'error', content: 'This is error event 4.' },
      ];
      break;
    default:
  }
  return listData || [];
}
function dateCellRender(value) {
  const listData = getListData(value);
  return (
    <ul className="events">
      {listData.map(item => (
        <li key={item.content}>
          <Badge status={item.type} text={item.content} />
        </li>
      ))}
    </ul>
  );
}
function getMonthData(value) {
  if (value.month() === 8) {
    return 1394;
  }
}
function monthCellRender(value) {
  const num = getMonthData(value);
  return num ? (
    <div className="notes-month">
      <section>{num}</section>
      <span>Backlog number</span>
    </div>
  ) : null;
}
ReactDOM.render(
  <Calendar dateCellRender={dateCellRender} monthCellRender={monthCellRender} />,
  mountNode,
);.events {
  margin: 0;
  padding: 0;
  list-style: none;
}
.events .ant-badge-status {
  width: 100%;
  overflow: hidden;
  font-size: 12px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.notes-month {
  font-size: 28px;
  text-align: center;
}
.notes-month section {
  font-size: 28px;
}2022
Feb
| Su | Mo | Tu | We | Th | Fr | Sa | 
|---|---|---|---|---|---|---|
30  | 31  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
13  | 14  | 15  | 16  | 17  | 18  | 19  | 
20  | 21  | 22  | 23  | 24  | 25  | 26  | 
27  | 28  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
import { Calendar } from 'antd';
function onPanelChange(value, mode) {
  console.log(value, mode);
}
ReactDOM.render(
  <div className="site-calendar-demo-card">
    <Calendar fullscreen={false} onPanelChange={onPanelChange} />
  </div>,
  mountNode,
);.site-calendar-demo-card {
  width: 300px;
  border: 1px solid #f0f0f0;
  border-radius: 2px;
}2017
Jan
| Su | Mo | Tu | We | Th | Fr | Sa | 
|---|---|---|---|---|---|---|
01  | 02  | 03  | 04  | 05  | 06  | 07  | 
08  | 09  | 10  | 11  | 12  | 13  | 14  | 
15  | 16  | 17  | 18  | 19  | 20  | 21  | 
22  | 23  | 24  | 25  | 26  | 27  | 28  | 
29  | 30  | 31  | 01  | 02  | 03  | 04  | 
05  | 06  | 07  | 08  | 09  | 10  | 11  | 
import { Calendar, Alert } from 'antd';
import moment from 'moment';
class App extends React.Component {
  state = {
    value: moment('2017-01-25'),
    selectedValue: moment('2017-01-25'),
  };
  onSelect = value => {
    this.setState({
      value,
      selectedValue: value,
    });
  };
  onPanelChange = value => {
    this.setState({ value });
  };
  render() {
    const { value, selectedValue } = this.state;
    return (
      <>
        <Alert
          message={`You selected date: ${selectedValue && selectedValue.format('YYYY-MM-DD')}`}
        />
        <Calendar value={value} onSelect={this.onSelect} onPanelChange={this.onPanelChange} />
      </>
    );
  }
}
ReactDOM.render(<App />, mountNode);Custom header
2022
2月
| Su | Mo | Tu | We | Th | Fr | Sa | 
|---|---|---|---|---|---|---|
30  | 31  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
13  | 14  | 15  | 16  | 17  | 18  | 19  | 
20  | 21  | 22  | 23  | 24  | 25  | 26  | 
27  | 28  | 01  | 02  | 03  | 04  | 05  | 
06  | 07  | 08  | 09  | 10  | 11  | 12  | 
import { Calendar, Select, Radio, Col, Row, Typography } from 'antd';
function onPanelChange(value, mode) {
  console.log(value, mode);
}
ReactDOM.render(
  <div className="site-calendar-customize-header-wrapper">
    <Calendar
      fullscreen={false}
      headerRender={({ value, type, onChange, onTypeChange }) => {
        const start = 0;
        const end = 12;
        const monthOptions = [];
        const current = value.clone();
        const localeData = value.localeData();
        const months = [];
        for (let i = 0; i < 12; i++) {
          current.month(i);
          months.push(localeData.monthsShort(current));
        }
        for (let index = start; index < end; index++) {
          monthOptions.push(
            <Select.Option className="month-item" key={`${index}`}>
              {months[index]}
            </Select.Option>,
          );
        }
        const month = value.month();
        const year = value.year();
        const options = [];
        for (let i = year - 10; i < year + 10; i += 1) {
          options.push(
            <Select.Option key={i} value={i} className="year-item">
              {i}
            </Select.Option>,
          );
        }
        return (
          <div style={{ padding: 8 }}>
            <Typography.Title level={4}>Custom header</Typography.Title>
            <Row gutter={8}>
              <Col>
                <Radio.Group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
                  <Radio.Button value="month">Month</Radio.Button>
                  <Radio.Button value="year">Year</Radio.Button>
                </Radio.Group>
              </Col>
              <Col>
                <Select
                  size="small"
                  dropdownMatchSelectWidth={false}
                  className="my-year-select"
                  onChange={newYear => {
                    const now = value.clone().year(newYear);
                    onChange(now);
                  }}
                  value={String(year)}
                >
                  {options}
                </Select>
              </Col>
              <Col>
                <Select
                  size="small"
                  dropdownMatchSelectWidth={false}
                  value={String(month)}
                  onChange={selectedMonth => {
                    const newValue = value.clone();
                    newValue.month(parseInt(selectedMonth, 10));
                    onChange(newValue);
                  }}
                >
                  {monthOptions}
                </Select>
              </Col>
            </Row>
          </div>
        );
      }}
      onPanelChange={onPanelChange}
    />
  </div>,
  mountNode,
);.site-calendar-customize-header-wrapper {
  width: 300px;
  border: 1px solid #f0f0f0;
  border-radius: 2px;
}API#
Note: Part of the Calendar's locale is read from value. So, please set the locale of moment correctly.
// The default locale is en-US, if you want to use other locale, just set locale in entry file globally.
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
<Calendar
  dateCellRender={dateCellRender}
  monthCellRender={monthCellRender}
  onPanelChange={onPanelChange}
  onSelect={onSelect}
/>| Property | Description | Type | Default | Version | 
|---|---|---|---|---|
| dateCellRender | Customize the display of the date cell, the returned content will be appended to the cell | function(date: moment): ReactNode | - | |
| dateFullCellRender | Customize the display of the date cell, the returned content will override the cell | function(date: moment): ReactNode | - | |
| defaultValue | The date selected by default | moment | - | |
| disabledDate | Function that specifies the dates that cannot be selected, currentDate is same moment object as value prop which you shouldn't mutate it](https://github.com/ant-design/ant-design/issues/30987) | (currentDate: moment) => boolean | - | |
| fullscreen | Whether to display in full-screen | boolean | true | |
| headerRender | Render custom header in panel | function(object:{value: moment, type: string, onChange: f(), onTypeChange: f()}) | - | |
| locale | The calendar's locale | object | (default) | |
| mode | The display mode of the calendar | month | year | month | |
| monthCellRender | Customize the display of the month cell, the returned content will be appended to the cell | function(date: moment): ReactNode | - | |
| monthFullCellRender | Customize the display of the month cell, the returned content will override the cell | function(date: moment): ReactNode | - | |
| validRange | To set valid range | [moment, moment] | - | |
| value | The current selected date | moment | - | |
| onChange | Callback for when date changes | function(date: moment) | - | |
| onPanelChange | Callback for when panel changes | function(date: moment, mode: string) | - | |
| onSelect | Callback for when a date is selected | function(date: moment) | - |