Show · Calendar

Calendar

Calendar component that allows to display corresponding events in day/week/month view

Demos

How to import

<script setup lang="ts">
    import { Calendar } from '@fibrous/semi-ui-vue';
</script>

Day Mode

Day mode. You could toggle the red line of current time using showCurrTime.

全天
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
Code
<script setup lang="ts">
    import { Calendar } from '@fibrous/semi-ui-vue';

    // A fixed date keeps the server render and the browser on the same first frame
    const displayValue = new Date(2026, 9, 25);
</script>

<template>
    <Calendar :displayValue="displayValue" mode="day" />
</template>

Week Mode

Week mode. You could toggle the red line of current time using showCurrTime.

10月
25周日
26周一
27周二
28周三
29周四
30周五
31周六
全天
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
Code
<script setup lang="ts">
    import { Calendar } from '@fibrous/semi-ui-vue';

    // A fixed date keeps the server render and the browser on the same first frame
    const displayValue = new Date(2026, 9, 25);
</script>

<template>
    <Calendar :displayValue="displayValue" mode="week" />
</template>

Month Mode

Month Mode.

周日
周一
周二
周三
周四
周五
周六
27
28
29
30
10月 1日
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Code
<script setup lang="ts">
    import { Calendar } from '@fibrous/semi-ui-vue';

    // A fixed date keeps the server render and the browser on the same first frame
    const displayValue = new Date(2026, 9, 25);
</script>

<template>
    <Calendar :displayValue="displayValue" mode="month" />
</template>

Set week start day

The day of the week can be set as the first day of the week through weekStartsOn, 0 for Sunday, 1 for Monday, and so on. Default is Sunday.
weekStartsOn takes effect for month view and week view.

周日
周一
周二
周三
周四
周五
周六
27
28
29
30
10月 1日
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Calendar, Radio, RadioGroup, type CalendarWeekStartsOn, type RadioValue } from '@fibrous/semi-ui-vue';

    const weekStartsOn = ref<RadioValue | undefined>(0);
    const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
    // A fixed date keeps the server render and the browser on the same first frame
    const displayValue = new Date(2026, 9, 25);
</script>

<template>
    <div>
        <RadioGroup v-model="weekStartsOn" aria-label="周起始日" name="demo-radio-group-vertical" type="button">
            <Radio v-for="(day, index) in days" :key="day" :value="index">{{ day }}</Radio>
        </RadioGroup>
        <Calendar :displayValue="displayValue" mode="month" :style="{ marginTop: '20px' }" :weekStartsOn="weekStartsOn as CalendarWeekStartsOn" />
    </div>
</template>

Range Mode

Range Mode. range is required which is a left-closed and right-open interval.

9月
26周六
27周日
28周一
29周二
30周三
全天
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
Code
<script setup lang="ts">
    import { Calendar } from '@fibrous/semi-ui-vue';

    const range = [new Date(2020, 8, 26), new Date(2020, 8, 31)];
</script>

<template>
    <Calendar mode="range" :range="range" />
</template>

Render Events

You could pass in an array of event objects to events to render items. For detailed format, refer to Event Object below.

The content of an event renders the text of children by default. Use the #event="{ event }" scoped slot for custom DOM: event is the original object from events and may carry any custom field. When one event is shown in several places (such as a multi-day event), the slot is called once for each place.





7月
21周日
22周一
23周二
24周三
25周四
26周五
27周六
全天
  • 6月25日 14:45 ~ 7月26日 6:18
  • 7月18日 10:00 ~ 7月30日 8:00
  • 7月19日 20:00 ~ 7月23日 14:00
  • 7月25日 8:00 ~ 7月27日 6:00
  • 7月21日 6:00 ~ 7月25日 6:00
  • 7月26日 10:00 ~ 7月27日 16:00
  • 7月22日 全天
  • 7月22日 9:00 ~ 7月23日 23:00
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
  • 7月23日 8:32
  • 7月23日 14:30-20:00
Code
<script setup lang="ts">
    import { computed, ref, type CSSProperties } from 'vue';
    import { Calendar, DatePicker, Radio, RadioGroup, type CalendarEventObject, type CalendarMode, type RadioValue } from '@fibrous/semi-ui-vue';

    const mode = ref<RadioValue | undefined>('week');
    const displayValue = ref<Date | undefined>(new Date(2019, 6, 23, 8, 32, 0));

    const onChangeDate = (value: Date | Date[] | undefined) => {
        if (!Array.isArray(value)) displayValue.value = value;
    };

    const dailyEventStyle: CSSProperties = {
        borderRadius: '3px',
        boxSizing: 'border-box',
        border: 'var(--semi-color-primary) 1px solid',
        padding: '10px',
        backgroundColor: 'var(--semi-color-primary-light-default)',
        height: '100%',
        overflow: 'hidden',
    };
    const allDayStyle: CSSProperties = {
        borderRadius: '3px',
        boxSizing: 'border-box',
        border: 'var(--semi-color-bg-1) 1px solid',
        padding: '2px 4px',
        backgroundColor: 'var(--semi-color-primary-light-active)',
        height: '100%',
        overflow: 'hidden',
    };
    // `daily` marks the events that keep the padded style outside the month view; any extra key is passed to #event.
    const events: CalendarEventObject[] = [
        {
            key: '0',
            start: new Date(2019, 5, 25, 14, 45, 0),
            end: new Date(2019, 6, 26, 6, 18, 0),
            children: '6月25日 14:45 ~ 7月26日 6:18',
        },
        {
            key: '1',
            start: new Date(2019, 6, 18, 10, 0, 0),
            end: new Date(2019, 6, 30, 8, 0, 0),
            children: '7月18日 10:00 ~ 7月30日 8:00',
        },
        {
            key: '2',
            start: new Date(2019, 6, 19, 20, 0, 0),
            end: new Date(2019, 6, 23, 14, 0, 0),
            children: '7月19日 20:00 ~ 7月23日 14:00',
        },
        {
            key: '3',
            start: new Date(2019, 6, 21, 6, 0, 0),
            end: new Date(2019, 6, 25, 6, 0, 0),
            children: '7月21日 6:00 ~ 7月25日 6:00',
        },
        { key: '4', allDay: true, start: new Date(2019, 6, 22, 8, 0, 0), children: '7月22日 全天' },
        {
            key: '5',
            start: new Date(2019, 6, 22, 9, 0, 0),
            end: new Date(2019, 6, 23, 23, 0, 0),
            children: '7月22日 9:00 ~ 7月23日 23:00',
        },
        {
            key: '6',
            daily: true,
            start: new Date(2019, 6, 23, 8, 32, 0),
            end: new Date(2019, 6, 23, 8, 42, 0),
            children: '7月23日 8:32',
        },
        {
            key: '7',
            daily: true,
            start: new Date(2019, 6, 23, 14, 30, 0),
            end: new Date(2019, 6, 23, 20, 0, 0),
            children: '7月23日 14:30-20:00',
        },
        {
            key: '8',
            start: new Date(2019, 6, 25, 8, 0, 0),
            end: new Date(2019, 6, 27, 6, 0, 0),
            children: '7月25日 8:00 ~ 7月27日 6:00',
        },
        {
            key: '9',
            start: new Date(2019, 6, 26, 10, 0, 0),
            end: new Date(2019, 6, 27, 16, 0, 0),
            children: '7月26日 10:00 ~ 7月27日 16:00',
        },
    ];
    const range = computed(() => (mode.value === 'range' ? [new Date(2019, 6, 23), new Date(2019, 6, 26)] : []));
</script>

<template>
    <RadioGroup v-model="mode" type="button">
        <Radio value="day">日视图</Radio>
        <Radio value="week">周视图</Radio>
        <Radio value="month">月视图</Radio>
        <Radio value="range">多日视图</Radio>
    </RadioGroup>
    <br />
    <br />
    <DatePicker :modelValue="displayValue" @update:modelValue="onChangeDate" />
    <br />
    <br />
    <Calendar :displayValue="displayValue" :events="events" :height="400" :minEventHeight="40" :mode="mode as CalendarMode" :range="range">
        <template #event="{ event }">
            <div :style="event.daily && mode !== 'month' ? dailyEventStyle : allDayStyle">{{ event.children }}</div>
        </template>
    </Calendar>
</template>

Custom Render

You could use the #dateGrid="{ date, dateString }" scoped slot to render customized date cell or column. Use absolute positioning for elements.

Custom Render Events

7月
21周日
22周一
23周二
24周三
25周四
26周五
27周六
全天
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
吃饭 🍰
睡觉 😪
打豆豆 🎮
Code
<script setup lang="ts">
    import type { CSSProperties } from 'vue';
    import { Calendar } from '@fibrous/semi-ui-vue';

    const dailyEventStyle: CSSProperties = {
        position: 'absolute',
        left: '0',
        right: '0',
        borderRadius: '3px',
        boxSizing: 'border-box',
        border: 'var(--semi-color-primary) 1px solid',
        padding: '10px',
        backgroundColor: 'var(--semi-color-primary-light-default)',
        overflow: 'hidden',
    };
    const displayValue = new Date(2019, 6, 23, 8, 32, 0);
    const targetDateString = new Date(2019, 6, 23).toString();
</script>

<template>
    <Calendar :displayValue="displayValue" :height="700" mode="week">
        <template #dateGrid="{ dateString }">
            <template v-if="dateString === targetDateString">
                <div :style="{ ...dailyEventStyle, top: '500px', height: '50px' }">吃饭 🍰</div>
                <div :style="{ ...dailyEventStyle, top: '0', height: '400px' }">睡觉 😪</div>
                <div :style="{ ...dailyEventStyle, top: '700px', height: '100px' }">打豆豆 🎮</div>
            </template>
        </template>
    </Calendar>
</template>

Customized Date Cell Style

You could also use #dateGrid to customize date cell style, e.g. backgroundColor. Please notice that in Month View, the date text on the right corner has a z-index of 3. Use a larger z-index if you would like to cover the text as well.

周日
周一
周二
周三
周四
周五
周六
30
7月 1日
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
8月 1日
2
3
Code
<script setup lang="ts">
    import type { CSSProperties } from 'vue';
    import { Calendar } from '@fibrous/semi-ui-vue';

    const importantDate: CSSProperties = {
        position: 'absolute',
        left: '0',
        right: '0',
        top: '0',
        bottom: '0',
        backgroundColor: 'var(--semi-color-danger-light-default)',
    };
    const displayValue = new Date(2019, 6, 23, 8, 32, 0);
    const importDates = [new Date(2019, 6, 2), new Date(2019, 6, 8), new Date(2019, 6, 19), new Date(2019, 6, 23)];
    const importDateStrings = importDates.map((date) => date.toString());
</script>

<template>
    <Calendar :displayValue="displayValue" :height="700" mode="month">
        <template #dateGrid="{ dateString }">
            <div v-if="importDateStrings.includes(dateString)" :style="importantDate" />
        </template>
    </Calendar>
</template>

Customized Date Render

You could use #dateDisplay="{ date }" to customize the display of date

5月
14
15
16
17
18
19
20
全天
上午1时
上午2时
上午3时
上午4时
上午5时
上午6时
上午7时
上午8时
上午9时
上午10时
上午11时
下午12时
下午1时
下午2时
下午3时
下午4时
下午5时
下午6时
下午7时
下午8时
下午9时
下午10时
下午11时
Code
<script setup lang="ts">
    import { Avatar, Calendar } from '@fibrous/semi-ui-vue';

    const displayValue = new Date(2023, 4, 14);
    const colors = ['amber', 'blue', 'cyan', 'green', 'grey', 'indigo', 'lime'] as const;
</script>

<template>
    <Calendar :displayValue="displayValue" :height="400" mode="week">
        <template #dateDisplay="{ date }">
            <div :style="{ paddingBlock: '6px' }">
                <Avatar :color="colors[date.getDay()]" size="small">{{ date.getDate() }}</Avatar>
            </div>
        </template>
    </Calendar>
</template>

API Reference

Calendar

Props

PropertyDescriptionTypeDefault
displayValueDisplay date. When omitted it is the current date and updates at midnight.DatesemiGlobalDefault("Calendar", "displayValue")
rangeDate range shown in range mode, left-closed and right-open. Required in range mode.Date[]semiGlobalDefault("Calendar", "range")
eventsEvents to render, see Event Object.EventObject[]semiDefault("Calendar", "events", [])
modeView mode: day, week, month or range. The view switches as soon as it changes.CalendarModesemiDefault("Calendar", "mode", "week")
showCurrTimeShows the red line of the current time in the day, week and range views.booleansemiDefault("Calendar", "showCurrTime", true)
weekStartsOnDay of the week that starts the week, 0 for Sunday, 1 for Monday and so on. Applies to the month and week views.WeekStartsOnsemiDefault("Calendar", "weekStartsOn", 0)
scrollTopDefault scroll offset of the content in the day, week and range views.numbersemiDefault("Calendar", "scrollTop", 400)
markWeekendShows weekend columns in grey to tell them from weekdays.booleansemiDefault("Calendar", "markWeekend", false)
minEventHeightMinimum height in pixels of events in the day, range and week views.numbersemiGlobalDefault("Calendar", "minEventHeight")
widthWidth of the calendar; a number is in pixels.string | numbersemiGlobalDefault("Calendar", "width")
heightHeight of the calendar; a number is in pixels.string | numbersemiDefault("Calendar", "height", 600)

Events

EventDescriptionCallback parameters
clickEmitted when a date cell is clicked, with the event and the date of the cell. The unit is half an hour in the day, week and range views and one day in the month view.[event: MouseEvent, value: Date]
closeEmitted when the card showing all events of a day closes in the month view: the click event for the close button or a second click on "N more", the keyboard event for Esc, and null for a click outside or when the component is deactivated in KeepAlive.[event: MouseEvent | KeyboardEvent | null]
moreClickEmitted when a click on "N more" opens the card in the month view, with the event, the date and the number of collapsed events. It is not emitted when a second click closes the card.[event: MouseEvent, date: Date, remaining: number]

Slots

SlotDescriptionScope parameters
headerCustom header content.any
eventCustom event content. event is the original object from events and the slot is called once for each place the event appears. The text of children is rendered when it is absent.CalendarEventSlotProps
dateDisplayCustom date text: the column titles of the week and range views and every cell of the month view. The day view does not use it.CalendarDateDisplaySlotProps
dateGridCustom content of a date cell or column, with the date and its dateString (date.toString()). Use absolute positioning for elements.CalendarDateGridSlotProps
timeDisplayCustom time text in the day, week and range views; time is the hour.CalendarTimeDisplaySlotProps
allDayEventsCustom area for events at the top of the day, range and week views; events is the whole events array that was passed in, to be filtered by the slot.CalendarAllDayEventsSlotProps

Exposes

NameDescriptionType
None

class, style and native attributes are passed through attrs to the root element of the current view; aria-label takes precedence over the default table name.

Event Object

events is an array of event objects.
An event needs at least a start or an end time to be valid; an event with neither is skipped with a warning. An all-day event with only an end time starts on the day of its end. A timed event with only one end is extended by 1 hour, without crossing into another day. The end time is exclusive: a timed event that ends exactly at 00:00 is shown only on its start day, with no extra segment on the next day.

PropertiesInstructionstypeDefault
allDayWhether it is an all-day eventbooleanfalse
childrenDisplayed content, rendered as text when no #event slot is providedstring | number-
endEnd time of the eventDate-
keyRequired and must be unique.string-
startStart time of the eventDate-
Other fieldsCustom fields are kept as they are for the #event slot (such as color, title)any-

Accessibility

Keyboard and Focus

  • The day, week and range views scroll, and the view itself is one Tab stop that the arrow keys scroll
  • In the month view, "N more" for the collapsed events is a button: Enter or Space opens the card of the day and moves focus to its close button; Esc or the close button closes the card and returns focus to "N more"
  • Clicks on a day cell or a time slot (onClick in React, @click in Vue) respond to the pointer only and have no keyboard equivalent

Content Guidelines

  • Both 12-hour and 24-hour clocks can be used when the time needs to be displayed
  • If the 12-hour clock is used, it needs to be used together with AM/PM. For details, please refer to Time Specification
  • For the abbreviation rules for month, week and time, please refer to Abbreviation Specification

Design Tokens

These are the component's internal Sass variables and cannot be overridden. To customize styles, override the --semi-* CSS variables (see the Design Token page) or write unlayered CSS rules.
Sass variableValueUsage
$color-calendar-bg-activevar(--semi-color-primary)今日标识颜色
$color-calendar-bgvar(--semi-color-bg-2)日历背景颜色
$color-calendar-text-activevar(--semi-color-bg-1)日历文字颜色 - 今日
$color-calendar_curr-bordervar(--semi-color-danger)当前时间标识线颜色
$color-calendar_currCircle-bg-defaultvar(--semi-color-danger)当前时间标识原点颜色
$color-calendar_date-text-defaultvar(--semi-color-text-0)日历文字颜色 - 当月
$color-calendar_day-bordervar(--semi-color-border)日历描边颜色
$color-calendar_day-text-defaultvar(--semi-color-text-2)日历文字颜色 - 非当月
$color-calendar_sticky-bgvar(--semi-color-bg-2)日历背景颜色 - 吸顶部分
$color-calendar_weekend-bgvar(--semi-color-fill-0)日历背景颜色 - 非工作日
$width-calendar_day-minWidth78px
$height-calendar_day_grid60px
$width-calendar_day_grid-minWidth130px
$height-calendar_time_grid$height-calendar_day_grid * 0.5
$height-calendar_allDay26px
$height-calendar_allDay-minHeight26px
$width-calendar_currCircle8px
$width-calendar_tag_col-minWidth70px
$height-calendar_month100%
$height-calendar_month_week_skeletion100%
$height-calendar_month_grid_wrappercalc(100% - 27px)
$width-calendar_card220px
$width-calendar_today_date24px
$height-calendar_today_date24px
$height-calendar_body_li24px
$height-calendar_day_scroll_wrappercalc(100% - 28px)
$height-calendar_week_scroll_wrappercalc(100% - 55px)
$height-calendar_month_skeletion_li100%
$height-calendar_month_grid_col100%
$height-calendar_month_week_row_event_month1em
$width-calendar-border-default1px
$width-calendar-border-thick1px
$spacing-calendar_ul_li-padding0
$spacing-calendar_ul_li-margin0
$spacing-calendar_sticky_top-top0
$spacing-calendar_sticky_top-right0
$spacing-calendar_sticky_top-left0
$spacing-calendar_sticky_left-left0
$spacing-calendar_event_day-left0
$spacing-calendar_event_day-right0
$spacing-calendar_custom_container-top0
$spacing-calendar_custom_container-right0
$spacing-calendar_custom_container-bottom0
$spacing-calendar_custom_container-left0
$spacing-calendar_currCircle-marginTop-4px
$spacing-calendar_currLine-left0
$spacing-calendar_currLine-right0
$spacing-calendar_allDay_tag-paddingRight8px
$spacing-calendar_allDay_content-paddingLeft0
$spacing-calendar_month_event_card_wrapper-paddingTop2px
$spacing-calendar_grid_row_span_child-paddingY0
$spacing-calendar_grid_row_span_child-paddingX4px
$spacing-calendar_skeleton_li_child-paddingTop4px
$spacing-calendar_month_event_card_close-marginRight-4px
$spacing-calendar_header_info_date-marginTop4px
$spacing-calendar_time-paddingRight8px
$spacing-calendar_time_item_span-top-10px
$spacing-calendar_tag_child-paddingRight8px
$spacing-calendar_skeletion_grid_row_li-paddingRight8px
$spacing-calendar_month_event_card_wrapper-right8px
$spacing-calendar_month_event_card_content-paddingY12px
$spacing-calendar_month_event_card_content-paddingX0
$spacing-calendar_month_event_card_ul_li-margin0
$spacing-calendar_month_event_card_ul_li-padding0
$spacing-calendar_header-marginY12px
$spacing-calendar_header-marginX20px
$spacing-calendar_body-padingY0
$spacing-calendar_body-padingX16px
$spacing-calendar_event_items-top31px
$spacing-calendar_event_items-right0
$spacing-calendar_event_items-bottom20px
$spacing-calendar_event_items-left0
$spacing-calendar_month_skeletion-left0
$spacing-calendar_month_skeletion-right0
$spacing-calendar_month_date-right4px
$radius-calendar_currCirclevar(--semi-border-radius-circle)日历选中日期标识圆角
$radius-calendar_today_datevar(--semi-border-radius-circle)日历选中日期标识圆角
$font-calendar_allDay_tag-lineHeight$height-calendar_allDay日历全天标识文字行高
$font-calendar_today_date-lineHeight24px
$font-calendar_day_allDay-lineHeight26px
$font-calendar_day_allDay-fontSize26px
$font-calendar_month_day-fontSize24px
$z-calendar_stickyTop20
$z-calendar_item5
$z-calendar_stickyLeft10
$z-calendar_curr8
$z-calendar_line3