Philosophy: separate logic & styles For performance, simplified logic, readability, structure & maintenance of your own code,
what can be done via CSS should be done via CSS. CSS classes will help you style your events,
cells, splits, etc.
Vue Cal provides the minimum needed CSS styles, not the nicest one: that makes it highly
customizable for all the scenarii and a breeze to override. You most likely don't need the !important flag.
report
Vue 2 has reached EOL, and so has Vue Cal legacy branch.
You can still use it for Vue 2 projects with npm i vue-cal@legacy, but
it will not receive further updates or support. Time to move on! 🚀
access_timeRecurring eventsaccess_timeDrag & drop multiple day eventsaccess_timeDrag & drop events on touch devicesaccess_timeFull Typescript supportaccess_timeFull SSR supportaccess_timeImprove multiple day events Month viewaccess_timePrevent event intersect. on drag/resizeaccess_timeHorizontal timeline
Wait! Before you dive in, make sure you place Vue Cal in a container that has a set height! (not auto or initial)
By default Vue Cal will take the full width & height of its container if it has a set height.
<!-- If the container has no height, set a height on vue-cal --><vue-calstyle="height: 250px" />
<!-- If the container has no height, set a height on vue-cal -->
<vue-cal style="height: 250px" />
Double click cell to go to a narrower view and click the title to go to a broader view.
By default the calendar theme is grey to match with most of web pages.
You can easily change the color theme (learn how): try this
24
25
26
27
28
<vue-cal:time="false"hide-weekends />
<vue-cal :time="false" hide-weekends />
priority_highFor all the options details, refer to the API section.
Extra-small, no timeline, hidden view selector & custom arrows (using the reserved slots arrow-prev & arrow-next).
With a hidden view selector, you can still navigate between the different views: double click cell to go to a narrower view, click title to go to a broader view.
You can easily change the calendar color theme or use the rounded-cells theme
by applying the corresponding CSS class on the <vuecal> tag.
E.g. vuecal--rounded-theme, vuecal--green-theme, vuecal--blue-theme.
Read more about calendar themes in the CSS Notes section.
Because Vue Cal has the potential out of the box, you can also use it as a date picker.
Apply the css class vuecal--date-picker to have the date picker layout below.
you can also disable the transitions to have a faster effect.
24
25
26
27
28
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
1
2
3
4
5
6
24
25
26
27
28
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
1
2
3
4
5
6
24
25
26
27
28
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
1
2
3
4
5
6
keyboard_arrow_upDate picker layout, no transition
To hide views, you can use the disable-views option and provide an array of views
to disable.
The views are not only hidden from the menu bar, they are totally disabled,
even when navigating from cells and title bar clicks.
By default all the views are visible and the default active view is the week view.
With the options minDate & maxDate, you can set a
time range of selectable cells. All the cells before and after are still visible but
will be disabled and not selectable.
You can still navigate through them with arrows.
In this example, the minimum date is set to 10 days behind and the maximum date to
10 days ahead.
wb_incandescentNotes
the min and max options accept a formatted string or plain Javascript Date object.
2 different CSS class are available on out of range cells: .before-min
& .after-max.
// Using Vue Cal Date Prototypes (activated by default).
computed:{minDate(){returnnewDate().subtractDays(10)},maxDate(){returnnewDate().addDays(10)}}
// Using Vue Cal Date Prototypes (activated by default).
computed: {
minDate () {
return new Date().subtractDays(10)
},
maxDate () {
return new Date().addDays(10)
}
}
You can use the disable-days option to provide an array of formatted dates
(e.g. 2020-09-18) to disable.
24
25
26
27
28
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
1
2
3
4
5
6
<!-- Using Vue Cal Date Prototypes (activated by default): subtractDays, format, addDays --><vue-calxsmallhide-view-selectorclick-to-navigate:time="false"active-view="month":disable-views="['week']":disable-days="[
new Date().subtractDays(2).format(),
new Date().format(),
new Date().addDays(2).format()
]"
></vue-cal>
<!-- Using Vue Cal Date Prototypes (activated by default): subtractDays, format, addDays -->
<vue-cal
xsmall
hide-view-selector
click-to-navigate
:time="false"
active-view="month"
:disable-views="['week']"
:disable-days="[
new Date().subtractDays(2).format(),
new Date().format(),
new Date().addDays(2).format()
]"
></vue-cal>
If you want to hide particular days of the week, you can use the hide-weekdays
option. It accepts an array of days to hide (day numbers),
starting at 1 for Monday, to 7 for Sunday.
This option will apply on month & week views.
If you want to hide Saturday and Sunday you can put `6, 7` in the array or use
hide-weekends in supplement of hide-weekdays.
You can show the weeks numbers column on the month view with the show-week-numbers option.
You can also provide a custom renderer to the weeks numbers cells through the week-number-cell slot.
priority_highRefer to the API section to read more about all the options.
Let you translate the calendar texts into your own language (locale).
Refer to the locale option in the API section to know more or if you want to provide a translation.
Try it in Codepen: Vue Cal - Internationalization.
<vue-cal :time="false" small active-view="year" locale="zh-cn" />
priority_highFor Vue Cal versions that don't support ESM (prior 4.3.4 on Vue 3 or 3.11.0 on Vue 2),
the locale file must be loaded separately: import 'vue-cal/dist/i18n/zh-cn.js'.
Alternative
If you need full control on the texts, you can alternatively provide an object containing all the
texts (start from the locale JSON file matching your language).
Keep in mind this is not the recommended way: texts may be added / modified / removed in the library
and your provided custom texts may not work anymore.
Always prefer the standard locales!
Timelines are only visible on week and day views.
This example has a set time range from 08:00 to 19:00, time step of 30 minutes (1 hour by default),
24-hour format, and hidden weekends.
24
25
26
27
28
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
<!-- Time-start time-end & time-step are expected in minutes. --><vue-cal:time-from="8 * 60":time-to="19 * 60":time-step="30"hide-weekends></vue-cal>
<!-- Time-start time-end & time-step are expected in minutes. -->
<vue-cal
:time-from="8 * 60"
:time-to="19 * 60"
:time-step="30"
hide-weekends>
</vue-cal>
priority_highFor all the options details, refer to the API section.
// `from` and `to` are expected in minutes.
constdailyHours={from:9*60,to:18*60,class:'business-hours'}// In your component's data, special hours from Monday to Friday.
// Note that you can provide an array of multiple blocks for the same day.
specialHours:{1:dailyHours,2:dailyHours,3:[{from:9*60,to:12*60,class:'business-hours'},{from:14*60,to:18*60,class:'business-hours'}],4:dailyHours,5:dailyHours}
// `from` and `to` are expected in minutes.
const dailyHours = { from: 9 * 60, to: 18 * 60, class: 'business-hours' }
// In your component's data, special hours from Monday to Friday.
// Note that you can provide an array of multiple blocks for the same day.
specialHours: {
1: dailyHours,
2: dailyHours,
3: [
{ from: 9 * 60, to: 12 * 60, class: 'business-hours' },
{ from: 14 * 60, to: 18 * 60, class: 'business-hours' }
],
4: dailyHours,
5: dailyHours
}
// In your component's data, special hours from Monday to Sunday (1 to 7).
// Note that you can provide an array of multiple blocks for the same day.
specialHours:{1:{from:8*60,to:17*60,class:'doctor-1',label:'Doctor 1Full day shift'},2:{from:9*60,to:18*60,class:'doctor-2',label:'Doctor 2Full day shift'},3:[{from:8*60,to:12*60,class:'doctor-1',label:'Doctor 1Morning shift'},{from:14*60,to:19*60,class:'doctor-3',label:'Doctor 3Afternoon shift'}],4:{from:8*60,to:17*60,class:'doctor-1',label:'Doctor 1Full day shift'},5:{from:9*60,to:18*60,class:'doctor-3',label:'Doctor 3Full day shift'},6:{from:9*60,to:18*60,class:'doctor-2',label:'Doctor 2Full day shift'},7:{from:7*60,to:20*60,class:'closed',label:'Closed'}}
// In your component's data, special hours from Monday to Sunday (1 to 7).
// Note that you can provide an array of multiple blocks for the same day.
specialHours: {
1: {
from: 8 * 60,
to: 17 * 60,
class: 'doctor-1',
label: 'Doctor 1 Full day shift'
},
2: {
from: 9 * 60,
to: 18 * 60,
class: 'doctor-2',
label: 'Doctor 2 Full day shift'
},
3: [
{
from: 8 * 60,
to: 12 * 60,
class: 'doctor-1',
label: 'Doctor 1 Morning shift'
},
{
from: 14 * 60,
to: 19 * 60,
class: 'doctor-3',
label: 'Doctor 3 Afternoon shift'
}
],
4: {
from: 8 * 60,
to: 17 * 60,
class: 'doctor-1',
label: 'Doctor 1 Full day shift'
},
5: {
from: 9 * 60,
to: 18 * 60,
class: 'doctor-3',
label: 'Doctor 3 Full day shift'
},
6: {
from: 9 * 60,
to: 18 * 60,
class: 'doctor-2',
label: 'Doctor 2 Full day shift'
},
7: {
from: 7 * 60,
to: 20 * 60,
class: 'closed',
label: 'Closed'
}
}
When you choose to show the time in vue-cal, the current time of today's date will
be marked with a line (scroll to the current time to see it).
The line position will be updated every time the calendar current view is re-rendered (by interacting).
You can easily customize the now-line as you wish via CSS.
Changing the line and arrow color is as easy as:
.vuecal__now-line {color:#06c;}
.vuecal__now-line {color: #06c;}
If you don't want this feature you can simply hide it: .vuecal__now-line {display: none}.
This feature has no impact on performance.
If you want the now line to keep accurate position even while your calendar is iddle, you can use the option
watchRealTime (see more in the API section).
By default the selected date is today. But if you get lost in time travel, you can add
a Today button to select Today's date with the option today-button.
Like navigation arrows, there is also a slot to customize as you want.
below are the default Today button on the left and a custom one with icon and tooltip on the right.
If you are not satisfied with the position of this button, you can also place it
outside of Vue Cal like so: You might want to change view as well when going to Today's date, here is an example how:Today Button
1
2
3
4
5
8
9
10
11
12
15
16
17
18
19
22
23
24
25
26
29
30
31
1
2
5
6
7
8
9
1
2
3
4
5
8
9
10
11
12
15
16
17
18
19
22
23
24
25
26
29
30
31
1
2
5
6
7
8
9
<vue-calref="vuecal"xsmallhide-weekends:disable-views="['years']":time="false"today-buttonactive-view="month":selected-date="selectedDate"><!-- Optional slot for the custom button. --><template#today-button><!-- Using Vuetify (but we prefer Wave UI 🤘) --><v-tooltip><template#activator="{ on }"><v-btnv-on="on"><v-icon>my_location</v-icon></v-btn><span>Go to Today's date</span></template></v-tooltip></template></vue-cal><button@click="selectedDate = new Date()">ANOTHER TODAY BUTTON</button>
<vue-cal
ref="vuecal"
xsmall
hide-weekends
:disable-views="['years']"
:time="false"
today-button
active-view="month"
:selected-date="selectedDate">
<!-- Optional slot for the custom button. -->
<template #today-button>
<!-- Using Vuetify (but we prefer Wave UI 🤘) -->
<v-tooltip>
<template #activator="{ on }">
<v-btn v-on="on">
<v-icon>my_location</v-icon>
</v-btn>
<span>Go to Today's date</span>
</template>
</v-tooltip>
</template>
</vue-cal>
<button @click="selectedDate = new Date()">ANOTHER TODAY BUTTON</button>
data:()=>({// Default to next new year eve.
selectedDate:newDate(newDate().getFullYear(),11,31)})
data: () => ({
// Default to next new year eve.
selectedDate: new Date(new Date().getFullYear(), 11, 31)
})
The events have associated dates but no time information.
Timeless events cannot be resized as they have no time or duration information.
Refer to the events option in the API section.
data:()=>({events:[{start:'2018-11-21',end:'2018-11-21',title:'Need to go shopping',content:'<i class="icon material-icons">shopping_cart</i>',class:'leisure'},{start:'2018-11-21',end:'2018-11-21',title:'Golf with John',content:'<i class="icon material-icons">golf_course</i>',class:'sport'},{start:'2018-11-22',end:'2018-11-22',title:'Dad\'s birthday!',content:'<i class="icon material-icons">cake</i>',class:'sport'}]
Read-only events (by default events are not editable) with custom HTML content and css class (for event types).
Note that the events are always selectable (drop shadow and higher z-index), even when uneditable.
The difference with timeless events is that a time is set in the start and end attributes of the events.
By passing a function to the option on-event-click or on-event-dblclick,
you can control what happens when you click or double click an event - on any view where the events are displayed.
The callback function you provide will receive 2 arguments:
event: the clicked calendar event's object
e: the associated javascript DOM event
wb_incandescentYou can set any custom attribute you want on an event, you will then be able to access it in the dialog box!
data:()=>({selectedEvent:{},showDialog:false,events:[{start:'2018-11-20 14:00',end:'2018-11-20 18:00',title:'Need to go shopping',icon:'shopping_cart',// Custom attribute.
content:'Click to see my shopping list',contentFull:'My shopping list is rather long:<br><ul><li>Avocados</li><li>Tomatoes</li><li>Potatoes</li><li>Mangoes</li></ul>',// Custom attribute.
class:'leisure'},{start:'2018-11-22 10:00',end:'2018-11-22 15:00',title:'Golf with John',icon:'golf_course',// Custom attribute.
content:'Do I need to tell how many holes?',contentFull:'Okay.<br>It will be a 18 hole golf course.',// Custom attribute.
class:'sport'}]}),methods:{onEventClick(event,e){this.selectedEvent=eventthis.showDialog=true// Prevent navigating to narrower view (default vue-cal behavior).
e.stopPropagation()}}
data: () => ({
selectedEvent: {},
showDialog: false,
events: [
{
start: '2018-11-20 14:00',
end: '2018-11-20 18:00',
title: 'Need to go shopping',
icon: 'shopping_cart', // Custom attribute.
content: 'Click to see my shopping list',
contentFull: 'My shopping list is rather long:<br><ul><li>Avocados</li><li>Tomatoes</li><li>Potatoes</li><li>Mangoes</li></ul>', // Custom attribute.
class: 'leisure'
},
{
start: '2018-11-22 10:00',
end: '2018-11-22 15:00',
title: 'Golf with John',
icon: 'golf_course', // Custom attribute.
content: 'Do I need to tell how many holes?',
contentFull: 'Okay.<br>It will be a 18 hole golf course.', // Custom attribute.
class: 'sport'
}
]
}),
methods: {
onEventClick (event, e) {
this.selectedEvent = event
this.showDialog = true
// Prevent navigating to narrower view (default vue-cal behavior).
e.stopPropagation()
}
}
When you define events the month view will display an events count per day.
You can use the option eventsCountOnYearView to show the events count on
years & year views as well.
You can customize the events count as you wish via CSS.
/* Default indicator is count, but you can override it with one of the following rules. *//* Dash indicator */
.vuecal__cell-events-count {width:18px;height:2px;color:transparent;}/* Dot indicator */
.vuecal__cell-events-count {width:4px;min-width:0;height:4px;padding:0;color:transparent;}/* Cell background indicator */
.vuecal__cell--has-events {background-color:#fffacd;}
.vuecal__cell-events-count {display:none;}
/* Default indicator is count, but you can override it with one of the following rules. */
/* Dash indicator */
.vuecal__cell-events-count {
width: 18px;
height: 2px;
color: transparent;
}
/* Dot indicator */
.vuecal__cell-events-count {
width: 4px;
min-width: 0;
height: 4px;
padding: 0;
color: transparent;
}
/* Cell background indicator */
.vuecal__cell--has-events {background-color: #fffacd;}
.vuecal__cell-events-count {display: none;}
With the option events-on-month-view, you can choose whether to display the events on the month view or not. events-on-month-view accepts a Boolean to show or hide, or the string 'short' to show only the event's title.
If events-on-month-view is set to true, all the informations are displayed, you can then hide
any event information via CSS.
If you want all the cells to have the same height on this view, this is also your call, you can do it via CSS.
The editable-events option allows or prevent all these actions when it is set to
true or false:
Edit the event title
Resize an event by dragging the resizer handle.
Not available if no timeline, not possible on background events.
Drag & drop an event (not from the editable title text selection and not from the resizer).
Not possible on background events.
Delete an event (by clicking and holding an event)
Create a new event (by clicking and dragging on a cell or clicking and holding on a cell)
Learn more about event creation in the create events
example.
But the editable-events option also accept an object to specifically allow or deny any of the
previously listed actions.
For instance this object only denies the drag action:
On top of the global actions allowance, you can deny each of these actions individually for each event with the event
attributes titleEditable: false, deletable: false,
draggable: false & resizable: false.
By default the delete button only appears at the top of the event with a set height (1.4em).
If you want a full-height delete button like in this example, you can apply the CSS class
.vuecal--full-height-delete to your <vue-cal> tag.
In this example, the event creation and drag ability are disabled to focus on edition and deletion.
47 ( 2018)
19
20
21
22
23
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
Doctor appointment
10:35 - 11:30
local_hospital
Dentist appointment
18:30 - 19:15
local_hospital
Boring event
14:00 - 17:30
block I am not draggable, not resizable and not deletable.
// In data.
events:[{start:'2018-11-20 14:00',end:'2018-11-20 17:30',title:'Boring event',content:'<i class="icon material-icons">block</i><br>I am not draggable, not resizable and not deletable.',class:'blue-event',deletable:false,resizable:false,draggable:false},// other events.
]
// In data.
events: [
{
start: '2018-11-20 14:00',
end: '2018-11-20 17:30',
title: 'Boring event',
content: '<i class="icon material-icons">block</i><br>I am not draggable, not resizable and not deletable.',
class: 'blue-event',
deletable: false,
resizable: false,
draggable: false
},
// other events.
]
The event creation is only possible on a day cell, so not on years & year views.
There are multiple ways to create an event, let's start with the default one.
priority_highWith the snapToTime option, you can make sure the event starts and end at specific
intervals of minutes.
E.g. :snap-to-time="15" will snap the event to the closest :00, :15, :30, :45 while dragging.
This option also applies on event resizing after the drag-creation.
Click and drag on a cell to create an event, downwards or upwards.Snap to time: 15minClear all the events
This event creation method can cause difficulty when the calendar allows a click on a cell to
navigate: a slightly slipping click would create an event instead of navigating.
For this reason, the dragToCreateThreshold option default is 15 pixels.
So if you try to click or double click, it will not create an event.
In this example, the event "drag-creation" only starts after dragging 15 pixels, which allows navigating
even with an accidental move while double-clicking.
try to double click on a cell to go to the day view with both dragToCreateThreshold to 15 and 0.
There are 3 other ways to create an event: on cell click & hold, on cell single/double click,
or programmatically.
priority_highEvent creation will not trigger with a single/double click or click & hold if your cursor is on an event.
Let's see the 3 cases in order of complexity:
On cell single or double click
As the cell-click & cell-dblclick emitted
events return a date and time at cursor position (refer to the
emitted events example),
you simply need to call the createEvent() function straight
away from cell-dblclick:
Then you can give custom event attributes as you wish:
// In methods.
customEventCreation(){constdateTime=prompt('Create event on (YYYY-MM-DD HH:mm)','2025-03-28 13:15')// Check if date format is correct before creating event.
if(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(dateTime)){this.$refs.vuecal.createEvent(// Formatted start date and time or JavaScript Date object.
dateTime,// Event duration in minutes (Integer).
120,// Custom event props (optional).
{title:'New Event',content:'yay! 🎉',class:'blue-event'})}elseif(dateTime)alert('Wrong date format.')}
// In methods.
customEventCreation () {
const dateTime = prompt('Create event on (YYYY-MM-DD HH:mm)', '2025-03-28 13:15')
// Check if date format is correct before creating event.
if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(dateTime)) {
this.$refs.vuecal.createEvent(
// Formatted start date and time or JavaScript Date object.
dateTime,
// Event duration in minutes (Integer).
120,
// Custom event props (optional).
{ title: 'New Event', content: 'yay! 🎉', class: 'blue-event' }
)
} else if (dateTime) alert('Wrong date format.')
}
Adding a dialog box to the cell click & hold behavior
By default, event will be created with these attributes:
{start:{Date},// Starting from the cursor position in the clicked day cell.
end:{Date},// Event start + 2 hours.
title:'',content:'',split/* if any */:{Integer | String}// The current day split id that was clicked.
}
{
start: {Date}, // Starting from the cursor position in the clicked day cell.
end: {Date}, // Event start + 2 hours.
title: '',
content: '',
split /* if any */: {Integer | String} // The current day split id that was clicked.
}
If you want to customize those attributes you can modify the event directly through
the callback function that you provide to :on-event-create as follows:
// :on-event-create="onEventCreate", in template.
/**
* @param event {Object} The newly created event that you can override.
* @param deleteEventFunction {Function} Allows you to delete this event programmatically.
* @return {Object | false} The event to be passed back to Vue Cal, or false to reject creation.
*/onEventCreate(event,deleteEventFunction){// You can modify event here and return it.
// You can also return false to reject the event creation.
returnevent}
// :on-event-create="onEventCreate", in template.
/**
* @param event {Object} The newly created event that you can override.
* @param deleteEventFunction {Function} Allows you to delete this event programmatically.
* @return {Object | false} The event to be passed back to Vue Cal, or false to reject creation.
*/
onEventCreate (event, deleteEventFunction) {
// You can modify event here and return it.
// You can also return false to reject the event creation.
return event
}
In this example, we are adding a dialog box to the cell click & hold.
The dialog box will allow you to set all the event attributes.
With the same method, you can open a dialog at the end of the event drag-creation.
24
25
26
27
28
10:00
11:00
12:00
13:00
14:00
15:00
This example uses the same dialog box and cancelEventCreation &
closeCreationDialog functions as the previous example.
Note that event-drag-create gets fired on mouseup of the drag-create,
whereas onEventCreate gets called as soon as the event appears on screen, while dragging.
data:()=>({selectedEvent:null,showEventCreationDialog:false}),methods:{// Called when drag-create threshold is reached (when the event appears on screen),
// but before releasing the drag; so, it should not open the dialog box yet.
onEventCreate(event,deleteEventFunction){this.selectedEvent=eventthis.deleteEventFunction=deleteEventFunctionreturnevent}}
data: () => ({
selectedEvent: null,
showEventCreationDialog: false
}),
methods: {
// Called when drag-create threshold is reached (when the event appears on screen),
// but before releasing the drag; so, it should not open the dialog box yet.
onEventCreate (event, deleteEventFunction) {
this.selectedEvent = event
this.deleteEventFunction = deleteEventFunction
return event
}
}
In addition to the obvious event dragging itself, there are quite a few things that are good
to know about the drag & drop.
priority_high
Drag & drop is a module (to keep Vue Cal light weight).
For Vue Cal versions that don't support ESM (prior 4.3.4 on Vue 3 or 3.11.0 on Vue 2),
it must be loaded separately: import 'vue-cal/dist/drag-and-drop.js'.
Drag & drop is only available on single day events for now.
Dragging over header
While you drag an event over the view selector buttons, or the previous and next arrows,
or even the today button, they will get into a highlighted state and if you hold over for
a few milliseconds they will change the view so you can drop the event you are holding
on another date of the calendar.
while dragged over, the previous and next buttons will keep changing the view until you go
away from the button.
Dragging an event over the today button will take you to Today's date, and if you're in
a years or year view it will also go to the next available
narrower view from month downwards.
Dragging over a cell
If you drag an event over a cell or a split
(ref. splitting days), the cell/split gets into a
highlighted state, showing you where the event would go if you drop it.
You can drop an event in any cell. But because it does not make much sense to drop it into a
years or year view, if you hold over a cell
in these views or in month view, it will go to the next available narrower
view so you can at least see a day cell.
Dropping the event into a cell or somewhere not allowed
If you drop the event outside of the calendar or anywhere it's not possible,
it will snap back to its original place and the original view will be restored if it
was changed by navigating away.
If you drop the event in a cell and it would start before midnight (00:00), it is placed at
midnight, keeping its duration.
If you drop the event in a cell and it would end after midnight (24:00), its duration will
be truncated to end at midnight (24:00).
By default, when you drop the event it will start exactly where you dropped it,
but if you prefer you can use the snapToTime option to dictate where it should
snap to (refer to snapToTime in the API section).
If you wonder why it does not represent the snapping while dragging, it's not possible to do it with
the native HTML5 drag & drop.
You can change the highlighted style of the header buttons or cells through these CSS classes:
.vuecal__view-btn--highlighted
.vuecal__today-btn--highlighted
.vuecal__arrow--highlighted
.vuecal__cell--highlighted
.vuecal__cell-split--highlighted
You can change the style of the event being dragged through the
.vuecal__event--dragging CSS class.
While dragging, a copy of the original event is made and that's what you drag
(native HTML5 drag & drop behavior). The original event receive the
.vuecal__event--static CSS class which hides it with opacity: 0.
You can use that class to give it a different style.
You can drag & drop events from an external source as long as they are HTML5 draggable (this will change when touch devices are supported).
It is also possible to move an event from one calendar to another.
In the external event, you can set a duration property: it will be used to represent the duration of the event on Vue Cal when it has no date.
If the duration is missing, the default will be 2 hours.
wb_incandescentImportant note when dragging external events into Vue Cal:
With HTML5 drag & drop, when you drop a DOM element to another location, you have to move
the element yourself. Now especially because Vue is data driven and a DOM update does not
modify the data, you will also have to remove the event from its original data source yourself
- unless you want to create a copy.
Learn how in the example source code below.
exportdefault{data:()=>({draggables:[{// The id (or however you name it), will help you find which event to delete
// from the callback triggered on drop into Vue Cal.
id:1,title:'Ext. Event 1',content:'content 1',duration:60},{id:2,title:'Ext. Event 2',content:'content 2',duration:30},{id:3,title:'Ext. Event 3',content:'content 3'// No defined duration here: will default to 2 hours.
}]}),methods:{onEventDragStart(e,draggable){// Passing the event's data to Vue Cal through the DataTransfer object.
e.dataTransfer.setData('event',JSON.stringify(draggable))e.dataTransfer.setData('cursor-grab-at',e.offsetY)},// The 3 parameters are destructured from the passed $event in @event-drop="onEventDrop".
// `event` is the final event as Vue Cal understands it.
// `originalEvent` is the event that was dragged into Vue Cal, it can come from the same
// Vue Cal instance, another one, or an external source.
// `external` is a boolean that lets you know if the event is not coming from any Vue Cal.
onEventDrop({event,originalEvent,external}){// If the event is external, delete it from the data source on drop into Vue Cal.
// If the event comes from another Vue Cal instance, it will be deleted automatically in there.
if(external){constextEventToDeletePos=this.draggables.findIndex(item=>item.id===originalEvent.id)if(extEventToDeletePos>-1)this.draggables.splice(extEventToDeletePos,1)}}}}
export default {
data: () => ({
draggables: [
{
// The id (or however you name it), will help you find which event to delete
// from the callback triggered on drop into Vue Cal.
id: 1,
title: 'Ext. Event 1',
content: 'content 1',
duration: 60
},
{
id: 2,
title: 'Ext. Event 2',
content: 'content 2',
duration: 30
},
{
id: 3,
title: 'Ext. Event 3',
content: 'content 3'
// No defined duration here: will default to 2 hours.
}
]
}),
methods: {
onEventDragStart (e, draggable) {
// Passing the event's data to Vue Cal through the DataTransfer object.
e.dataTransfer.setData('event', JSON.stringify(draggable))
e.dataTransfer.setData('cursor-grab-at', e.offsetY)
},
// The 3 parameters are destructured from the passed $event in @event-drop="onEventDrop".
// `event` is the final event as Vue Cal understands it.
// `originalEvent` is the event that was dragged into Vue Cal, it can come from the same
// Vue Cal instance, another one, or an external source.
// `external` is a boolean that lets you know if the event is not coming from any Vue Cal.
onEventDrop ({ event, originalEvent, external }) {
// If the event is external, delete it from the data source on drop into Vue Cal.
// If the event comes from another Vue Cal instance, it will be deleted automatically in there.
if (external) {
const extEventToDeletePos = this.draggables.findIndex(item => item.id === originalEvent.id)
if (extEventToDeletePos > -1) this.draggables.splice(extEventToDeletePos, 1)
}
}
}
}
Multiple day events work like a set of single day events linked together.
Deleting one of the day of a multiple day event, will also delete all the other days.
Updating the duration by dragging or changing the title will also update on all the days.
Try to resize, rename and delete the events. You can also resize horizontally thanks to
the option resize-x.
Drag & drop is not available on multiple day events for now.
wb_incandescent3 CSS classes are available to target the event first day, the last day and all the days in between:
event-start, event-middle, event-end.
Every week - by providing a every: "week" property.
Every month - by providing a every: "month" property.
Every year - by providing a every: "year" property.
Every specific week days - by providing a weekdays array containing the weekdays numbers (1 to 7 for Sunday).
Every `x` days - by providing a every: x property, with x being an integer.
Forever; Or until an expiry date if you provide an until: {String | Date} property.
Whether it's single-day, multiple-day, background, all-day, with time or timeless.
// month view event count => OK.
// @todo: check years/year views event counts.
// @todo: repeated multiple-day events does not appear if the first day is not in view (e.g. hide weekend).
// @todo: on month view with show events, occurrences don't appear on out of scope days.
// @todo: overlapping does not work.
// @todo: if 2 occurences are in the same day (multiple-day events), only one is shown.
// @todo: check all the above points one by one.
// month view event count => OK.
// @todo: check years/year views event counts.
// @todo: repeated multiple-day events does not appear if the first day is not in view (e.g. hide weekend).
// @todo: on month view with show events, occurrences don't appear on out of scope days.
// @todo: overlapping does not work.
// @todo: if 2 occurences are in the same day (multiple-day events), only one is shown.
// @todo: check all the above points one by one.
Recurrring events work like a set of single day events linked together.
That means, deleting, resizing or editing one of the day will apply to all the other days.
data:()=>({events:[{start:'2018-11-19 22:00',end:'2018-11-20 11:00',title:'Nightclub',content:'<i class="icon material-icons">local_drink</i>',class:'leisure',repeat:{weekdays:[1,3],// You can repeat on multiple days of the week.
until:'2020-11-30'// Don't need a time here as it will take the same as original event date.
}},{start:'2018-11-23',// You can put time or not, will be discarded if all-day.
end:'2018-11-23',title:'Pizza day!',content:'<i class="icon material-icons">local_pizza</i>',class:'pink-event',allDay:true,repeat:{weekdays:[5]// If original event day is not in these days, original event will still show up.
// Without `until` property, it will go on forever.
}},{start:'2018-11-22 10:00',end:'2018-11-22 12:00',title:'Piano lesson',content:'<i class="icon material-icons">queue_music</i>',class:'leisure',repeat:{every:'week',until:newDate('2019/06/01')// You can also use a Javascript Date.
}},{start:'2018-11-20 18:00',end:'2018-11-20 20:00',title:'Tennis tournament',content:'<i class="icon material-icons">sports_tennis</i>',class:'sport',repeat:{every:14,until:'2019-01-20'}},{start:'2018-11-01',end:'2018-11-01',title:'Crêpes day',content:'<i class="icon material-icons">restaurant</i>',class:'yellow-event',allDay:true,repeat:{every:'month',until:'2019-12-26'}},{start:'2015-06-15',end:'2015-06-15',title:'My Birthday',content:'<i class="icon material-icons">cake</i><br>I am 4.',class:'blue-event',allDay:true,repeat:{every:'year'}}]})
data: () => ({
events: [
{
start: '2018-11-19 22:00',
end: '2018-11-20 11:00',
title: 'Nightclub',
content: '<i class="icon material-icons">local_drink</i>',
class: 'leisure',
repeat: {
weekdays: [1, 3], // You can repeat on multiple days of the week.
until: '2020-11-30' // Don't need a time here as it will take the same as original event date.
}
},
{
start: '2018-11-23', // You can put time or not, will be discarded if all-day.
end: '2018-11-23',
title: 'Pizza day!',
content: '<i class="icon material-icons">local_pizza</i>',
class: 'pink-event',
allDay: true,
repeat: {
weekdays: [5] // If original event day is not in these days, original event will still show up.
// Without `until` property, it will go on forever.
}
},
{
start: '2018-11-22 10:00',
end: '2018-11-22 12:00',
title: 'Piano lesson',
content: '<i class="icon material-icons">queue_music</i>',
class: 'leisure',
repeat: {
every: 'week',
until: new Date('2019/06/01') // You can also use a Javascript Date.
}
},
{
start: '2018-11-20 18:00',
end: '2018-11-20 20:00',
title: 'Tennis tournament',
content: '<i class="icon material-icons">sports_tennis</i>',
class: 'sport',
repeat: {
every: 14,
until: '2019-01-20'
}
},
{
start: '2018-11-01',
end: '2018-11-01',
title: 'Crêpes day',
content: '<i class="icon material-icons">restaurant</i>',
class: 'yellow-event',
allDay: true,
repeat: {
every: 'month',
until: '2019-12-26'
}
},
{
start: '2015-06-15',
end: '2015-06-15',
title: 'My Birthday',
content: '<i class="icon material-icons">cake</i><br>I am 4.',
class: 'blue-event',
allDay: true,
repeat: {
every: 'year'
}
}
]
})
Overlapping, editable & deletable events.
Try to resize & delete events to see the overlapping redrawn.
Optionally you can set a min width (in percent) to the events:addAdd min-event-width
priority_highIn some cases you may want to set the events overlaps calculation only per same time step
(default time step is 1 hour), like in
this use case.
You can achieve this event overlaps grouping with the option overlaps-per-time-step.
Just add the property background: true to your events.
The particularity of the background events is that they can fully be overlapped but not overlapping.
They are not affected by other events: they stay in the background occupying the whole cell/split width.
Note that you can still temporarily raise a background event on top of others (z-index) by hovering it or clicking it.
Refer to the events option in the API section.
When the showAllDayEvents is set to true the events with an
allDay attribute set to true will be displayed in a fixed top
bar on the week & day views.
The all day events bar will only show up if the options showAllDayEvents &
time are set to true. time is important since without time information every event is an all-day
event there is no point in separating them then.
When showAllDayEvents is set to false, all the all day events
(allDay attribute set to true), will show up as a normal
background event.
On month view, switching showAllDayEvents on and off will not have any impact
since both should display the all day events.
showAllDayEvents accepts a Boolean or the string
'short', to display only the event title.
priority_highMultiple-day events feature will be improved in a future version to display across
multiple cells in the all day bar.
Split each day into multiple containers passing a CSS class & a label per split, and allow split-specific events.
By default the body of the calendar will fit the container.
But with the options min-cell-width or min-split-width, you can increase the calendar
body width and it will become scrollable horizontally.
min-cell-width.black will only be activated on week view, since there is only 1 cell in day view.
If both min-cell-width and min-split-width are set, min-split-width will be used.
You can also use the option sticky-split-labels to place the split labels in the header.
You can toggle the splits thanks to the hide property of each split in splitDays.
Refer to the min-cell-width.black, min-split-width and splitDays option in the API section.
closeMin cell width: 400pxaddAdd min split widthaddSticky Split LabelscloseHide Dad
data:()=>({stickySplitLabels:false,minCellWidth:400,minSplitWidth:0,splitDays:[// The id property is added automatically if none (starting from 1), but you can set a custom one.
// If you need to toggle the splits, you must set the id explicitly.
{id:1,class:'mom',label:'Mom'},{id:2,class:'dad',label:'Dad',hide:false},{id:3,class:'kid1',label:'Kid 1'},{id:4,class:'kid2',label:'Kid 2'},{id:5,class:'kid3',label:'Kid 3'}]events:[{start:'2018-11-19 10:35',end:'2018-11-19 11:30',title:'Doctor appointment',content:'<i class="icon material-icons">local_hospital</i>',class:'health',split:1// Has to match the id of the split you have set (or integers if none).
},{start:'2018-11-19 18:30',end:'2018-11-19 19:15',title:'Dentist appointment',content:'<i class="icon material-icons">local_hospital</i>',class:'health',split:2},{start:'2018-11-20 18:30',end:'2018-11-20 20:30',title:'Crossfit',content:'<i class="icon material-icons">fitness_center</i>',class:'sport',split:1},...]})
data: () => ({
stickySplitLabels: false,
minCellWidth: 400,
minSplitWidth: 0,
splitDays: [
// The id property is added automatically if none (starting from 1), but you can set a custom one.
// If you need to toggle the splits, you must set the id explicitly.
{ id: 1, class: 'mom', label: 'Mom' },
{ id: 2, class: 'dad', label: 'Dad', hide: false },
{ id: 3, class: 'kid1', label: 'Kid 1' },
{ id: 4, class: 'kid2', label: 'Kid 2' },
{ id: 5, class: 'kid3', label: 'Kid 3' }
]
events: [
{
start: '2018-11-19 10:35',
end: '2018-11-19 11:30',
title: 'Doctor appointment',
content: '<i class="icon material-icons">local_hospital</i>',
class: 'health',
split: 1 // Has to match the id of the split you have set (or integers if none).
},
{
start: '2018-11-19 18:30',
end: '2018-11-19 19:15',
title: 'Dentist appointment',
content: '<i class="icon material-icons">local_hospital</i>',
class: 'health',
split: 2
},
{
start: '2018-11-20 18:30',
end: '2018-11-20 20:30',
title: 'Crossfit',
content: '<i class="icon material-icons">fitness_center</i>',
class: 'sport',
split: 1
},
...
]
})
/* You can easily set a different style for each split of your days. */
.vuecal__cell-split.dad {background-color:rgba(221, 238, 255, 0.5);}
.vuecal__cell-split.mom {background-color:rgba(255, 232, 251, 0.5);}
.vuecal__cell-split.kid1 {background-color:rgba(221, 255, 239, 0.5);}
.vuecal__cell-split.kid2 {background-color:rgba(255, 250, 196, 0.5);}
.vuecal__cell-split.kid3 {background-color:rgba(255, 206, 178, 0.5);}
.vuecal__cell-split .split-label {color:rgba(0, 0, 0, 0.1);font-size:26px;}/* Different color for different event types. */
.vuecal__event.leisure {background-color:rgba(253, 156, 66, 0.9);border:1pxsolidrgb(233, 136, 46);color:#fff;}
.vuecal__event.health {background-color:rgba(164, 230, 210, 0.9);border:1pxsolidrgb(144, 210, 190);}
.vuecal__event.sport {background-color:rgba(255, 102, 102, 0.9);border:1pxsolidrgb(235, 82, 82);color:#fff;}
/* You can easily set a different style for each split of your days. */
.vuecal__cell-split.dad {background-color: rgba(221, 238, 255, 0.5);}
.vuecal__cell-split.mom {background-color: rgba(255, 232, 251, 0.5);}
.vuecal__cell-split.kid1 {background-color: rgba(221, 255, 239, 0.5);}
.vuecal__cell-split.kid2 {background-color: rgba(255, 250, 196, 0.5);}
.vuecal__cell-split.kid3 {background-color: rgba(255, 206, 178, 0.5);}
.vuecal__cell-split .split-label {color: rgba(0, 0, 0, 0.1);font-size: 26px;}
/* Different color for different event types. */
.vuecal__event.leisure {background-color: rgba(253, 156, 66, 0.9);border: 1px solid rgb(233, 136, 46);color: #fff;}
.vuecal__event.health {background-color: rgba(164, 230, 210, 0.9);border: 1px solid rgb(144, 210, 190);}
.vuecal__event.sport {background-color: rgba(255, 102, 102, 0.9);border: 1px solid rgb(235, 82, 82);color: #fff;}
Vue Cal emits events that you can listen to, to trigger an action outside of Vue Cal.
If you are not familiar with Vue JS events, you should read about it here:
vuejs.org/v2/guide/events.html open_in_new
Here is the list of emitted events:
View-related
ready
view-change
cell-click - returns a JS native Date object
cell-dblclick - returns a JS native Date object
cell-contextmenu - returns a JS native Date object and x, y: the cursor coordinates.
cell-keypress-enter - returns a JS native Date object
cell-focus - returns a JS native Date object
wb_incandescent
cell-click is fired every time you click a day, whereas
cell-focus is fired only when the selected day changes.
cell-click, cell-dblclick, cell-contextmenu
and cell-focus return the time at cursor position, unless the cell
was focused from tab key.
It would then return the cell start date (at midnight).
If split-days is provided, cell-click, cell-dblclick, cell-keypress-enter
and cell-focus emitted events will return an object containing the date and the clicked split id.
priority_highThe emitted events ready & view-change return an object:
{view:[String],startDate:[Date],// View start - JS native Date object.
endDate:[Date],// View end - JS native Date object.
firstCellDate:[Date],// Month view only, in case cell is out of current month - JS native Date object.
lastCellDate:[Date],// Month view only, in case cell is out of current month - JS native Date object.
outOfScopeEvents:[Array],// Month view only, all the events that are out of the current month.
events:[Array],// All the events in the current view.
week:[Integer]// Week number. Only returned if view is 'week'.
}
{
view: [String],
startDate: [Date], // View start - JS native Date object.
endDate: [Date], // View end - JS native Date object.
firstCellDate: [Date], // Month view only, in case cell is out of current month - JS native Date object.
lastCellDate: [Date], // Month view only, in case cell is out of current month - JS native Date object.
outOfScopeEvents: [Array], // Month view only, all the events that are out of the current month.
events: [Array], // All the events in the current view.
week: [Integer] // Week number. Only returned if view is 'week'.
}
Note that on a month view, the events from the out of scope days
(cells before and after the current month) are also returned in the array.
Events-related
event-focus - returns the associated calendar event object.
event-mouse-enter - returns the associated calendar event object.
event-mouse-leave - returns the associated calendar event object.
event-create - returns the associated calendar event object.
event-drag-create(only fired on mouseup after the event drag creation)
Returns the associated calendar event object.
event-delete - returns the associated calendar event object.
event-title-change - returns an object containing:
event, the calendar event object that was dropped
oldTitle, the title of the event before it was edited
event-duration-change(only fired at the end of the event resizing) Returns an object containing:
event, the calendar event object that was resized
oldDate, the Javascript Date the event was ending at before resize
originalEvent, the same calendar event before the change
event-resizingFired repeatedly while resizing For performance while dragging, returns a lighter object containing:
_eid, the calendar event internal id.
end, the calendar event new end Date.
endTimeMinutes, the calendar event new end time in minutes.
priority_highYou should only listen to this event if you have no choice. In most of cases you should
listen to event-duration-change instead (fired only once at the end of the resizing).
event-drop- returns an object containing:
event, the calendar event object that was dropped
oldDate, the Javascript Date the event was starting from before drag
newDate, the Javascript Date the event is now starting from
oldSplit only if splitting days, the id of the split the event came from
newSplit only if splitting days, the id of the split the event is dropped into
event-change - returns an object containing:
event, the calendar event object that was changed
originalEvent, the same calendar event before the change
(null when creating event)
wb_incandescent
The event-change emitted event groups all the events triggered on a calendar event property change:
event-title-change, event-drop,
event-duration-change and event-create. So you have the choice to listen to
event-change to cover any calendar event change or listen to a specific action emitted event.
To help you manipulate an event's date, Vue Cal returns native Date
objects in the event properties start & end.
So for instance, you can easily access the day of the week of an event with event.start.getDay().
You can then use Vue Cal Date prototypes to manipulate and format the Date as you want.
Watch the list of emitted events (latest on top) as you play with Vue Cal:
You can access any Vue Cal internal method through Vue refs.
This example shows how to control the Previous, Next and Today functions and the view selections
from external buttons.
One important thing to notice is that you can use a v-model on the active-view (or :active-view.sync for Vue 2)
in order to keep your variable updated when Vue Cal changes the view internally. For instance when you click the title to go
to a broader view.
A v-model can also be used on the selected-date (or :selected-date.sync for Vue 2)
In this example the right calendar is used as a date picker and the selected date is
updated on the left calendar via the @cell-focus event listener.
To know more about emitted events refer to the
emitted events example.
wb_incandescentIt is possible to modify the array of events like adding or removing an event
after the first load, but be aware that by doing so all the events in Vue Cal
will be replaced by the new array of events. You may lose your changes if you
modified events within Vue Cal.
addAdd an eventremoveRemove last event
Here is the live array of event titles:
[
"Doctor appointment",
"Doctor appointment",
"Doctor appointment",
"Dentist appointment",
"Crossfit",
"Brunch with Jane",
"Swimming lesson",
"Macca's with Mark",
"Movie time",
"Another movie tonight",
"Recall Dave",
"Eat pop corns",
"Enjoy the movie"
]
47 ( 2018)
19
20
21
22
23
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
Doctor appointment
10:35 - 11:30
local_hospital
Dentist appointment
18:30 - 19:15
local_hospital
Crossfit
18:30 - 20:30
fitness_center
Brunch with Jane
11:00 - 13:00
local_cafe
Recall Dave
12:00 - 12:30
local_cafe
Swimming lesson
19:30 - 23:00
pool
Macca's with Mark
12:30 - 13:00
fastfood
Movie time
21:00 - 23:30
local_play
Eat pop corns
21:00 - 23:30
local_play
Enjoy the movie
21:00 - 23:30
local_play
<button@click="events.push({
start: '2018-11-20 12:00',
end: '2018-11-20 17:00',
title: 'A new event',
class: 'blue-event'
})">Add an event</button><button@click="events.pop()">Remove last event</button><vue-calselected-date="2018-11-19":time-from="9 * 60":time-to="23 * 60":disable-views="['years', 'year', 'month']"hide-weekends:events="events"></vue-cal>
<button
@click="events.push({
start: '2018-11-20 12:00',
end: '2018-11-20 17:00',
title: 'A new event',
class: 'blue-event'
})">Add an event</button>
<button @click="events.pop()">Remove last event</button>
<vue-cal
selected-date="2018-11-19"
:time-from="9 * 60"
:time-to="23 * 60"
:disable-views="['years', 'year', 'month']"
hide-weekends
:events="events">
</vue-cal>
It is quite easy to scroll to a particular time, and the user has the choice to add this outside of Vue Cal.
wb_incandescentBear in mind that IE11 needs a polyfill before you can use the scrollTo method on a DOM element, this single line will do.
// For IE11. Adds this to your page once (in `created` hook for instance).
if(!HTMLElement.prototype.scrollTo)HTMLElement.prototype.scrollTo=function({top}){this.scrollTop=top}
// For IE11. Adds this to your page once (in `created` hook for instance).
if (!HTMLElement.prototype.scrollTo) HTMLElement.prototype.scrollTo = function ({ top }) { this.scrollTop = top }
vertical_align_bottomScroll to current timevertical_align_topScroll to top
// `timeCellHeight` is set to 26 in the component data.
scrollToCurrentTime(){constcalendar=document.querySelector('#vuecal .vuecal__bg')consthours=this.now.getHours()+this.now.getMinutes()/60calendar.scrollTo({top:hours*this.timeCellHeight,behavior:'smooth'})},scrollToTop(){constcalendar=document.querySelector('#vuecal .vuecal__bg')calendar.scrollTo({top:0,behavior:'smooth'})}
// `timeCellHeight` is set to 26 in the component data.
scrollToCurrentTime () {
const calendar = document.querySelector('#vuecal .vuecal__bg')
const hours = this.now.getHours() + this.now.getMinutes() / 60
calendar.scrollTo({ top: hours * this.timeCellHeight, behavior: 'smooth' })
},
scrollToTop () {
const calendar = document.querySelector('#vuecal .vuecal__bg')
calendar.scrollTo({ top: 0, behavior: 'smooth' })
}
If you want to have more fancy time cells, you can override them with the
time-cell-height option (in pixels) and scoped slots.
For even more flexibility, the horizontal lines are painted when you set the CSS class line on the tag you choose.
So if you don't set this class you are free to paint the lines yourself or not.
wb_incandescentUsing Vue.js scoped slots, you can also override the counting events method if you need.
If you are not familiar with scoped slots and destructuring slot-scope, you should first read about it:
vuejs.org/guide/components/slots.htm open_in_new
In the following example, we only count the events which have the custom
leisure CSS class (orange color).
Alternatively, you could also use the cell-content slot
instead of the events-count slot to perform the same task:
(Refer to the next example to know more:
Custom title & cells)
wb_incandescentUsing Vue.js scoped slots, you can override the calendar main date title and calendar cells.
If you are not familiar with scoped slots and destructuring slot-scope, you should first read about it:
vuejs.org/guide/components/slots.htm open_in_new
keyboard_arrow_rightCustom title
2 arguments are available through the scoped slot: #title="{ title, view }"
title, the formatted title (different on all the views). E.g."Week 2 (January 2019)"
view, an object containing the active view info.
{id:{String},// Current view, one of: years, year, month, week, day.
startDate:{Date},// JavaScript Date object.
endDate:{Date},// JavaScript Date object.
selectedDate:{Date}// JavaScript Date object.
}
{
id: {String}, // Current view, one of: years, year, month, week, day.
startDate: {Date}, // JavaScript Date object.
endDate: {Date}, // JavaScript Date object.
selectedDate: {Date} // JavaScript Date object.
}
You can use one or the other to format the title as you wish.
Using the pre-formatted title will be easy but not very flexible.
If you render the date yourself from view.startDate, don't forget
the different formats for all the views: years, year, month, week, day.
keyboard_arrow_rightCustom cells
In this example, only the cell number is clickable on month view.
5 arguments are available through the scoped slot: #cell-content="{ cell, view, split, events, goNarrower }"
cell, object containing the cell date.
{content:{String},// Pre-formatted cell content if any.
startDate:{Date},// JavaScript Date object.
endDate:{Date},// JavaScript Date object.
formattedDate:{String},// formatted start date. E.g. "2019-04-05".
today:{Boolean}}
{
content: {String}, // Pre-formatted cell content if any.
startDate: {Date}, // JavaScript Date object.
endDate: {Date}, // JavaScript Date object.
formattedDate: {String}, // formatted start date. E.g. "2019-04-05".
today: {Boolean}
}
view, object containing the active view info.
{id:{String},// Current view, one of: years, year, month, week, day.
startDate:{Date},// JavaScript Date object.
endDate:{Date},// JavaScript Date object.
selectedDate:{Date}// JavaScript Date object.
}
{
id: {String}, // Current view, one of: years, year, month, week, day.
startDate: {Date}, // JavaScript Date object.
endDate: {Date}, // JavaScript Date object.
selectedDate: {Date} // JavaScript Date object.
}
split, when splitting days, object containing the current split info.
events, array containing all the events of the current cell or split.
goNarrower, function to navigate to narrower view if possible.
priority_highBy default a cell is rendered as follows.
It is a good idea to reuse the same CSS classes as the different elements have associated styles:
<divclass="vuecal__flex vuecal__cell-content">
<div class="vuecal__flex vuecal__cell-content">
Now this is the part you can customize:
<!-- Will be added if splitting days and split labels are set --><divclass="split-label" /><!-- Will be added on years, year & month view --><divclass="vuecal__cell-date" /><!-- Will be added on month view --><divclass="vuecal__cell-events-count" /><!-- Will be added on week and day view if no event --><divclass="vuecal__no-event" />
Now this is the part you can customize:
<!-- Will be added if splitting days and split labels are set -->
<div class="split-label" />
<!-- Will be added on years, year & month view -->
<div class="vuecal__cell-date" />
<!-- Will be added on month view -->
<div class="vuecal__cell-events-count" />
<!-- Will be added on week and day view if no event -->
<div class="vuecal__no-event" />
<divclass="vuecal__cell-events" /></div>
<div class="vuecal__cell-events" />
</div>
🎉 2025 🎉
24
25
26
27
28
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
1
2
3
4
5
6
<vue-cal:time="false":dblclick-to-navigate="false"active-view="month":events="events"><!-- Custom title --><template#title="{ title, view }">
🎉
<spanv-if="view.id === 'years'">Years</span><!-- Using Vue Cal injected Date prototypes --><spanv-else-if="view.id === 'year'">{{ view.startDate.format('YYYY') }}</span><spanv-else-if="view.id === 'month'">{{ view.startDate.format('MMMM YYYY') }}</span><spanv-else-if="view.id === 'week'">w{{ view.startDate.getWeek() }} ({{ view.startDate.format('MMM YYYY') }})</span><spanv-else-if="view.id === 'day'">{{ view.startDate.format('dddd D MMMM (YYYY)') }}</span>
🎉
</template><!-- Custom cells --><template#cell-content="{ cell, view, events, goNarrower }"><spanclass="vuecal__cell-date":class="view.id"v-if="view.id === 'day'"@click="goNarrower">
{{ cell.date.getDate() }}
</span><spanclass="vuecal__cell-events-count"v-if="view.id === 'month' && events.length">{{ events.length }}</span><spanclass="vuecal__no-event"v-if="['week', 'day'].includes(view.id) && !events.length">Nothing here 👌</span></template><!-- Alternatively to custom cells if you just want custom no-event text: --><!-- <template #no-event>Nothing here 👌</template> --></vue-cal>
priority_highBy default an event is rendered as follows.
It is a good idea to reuse the same CSS classes as the different elements have associated styles:
<divclass="vuecal__event"><!-- Will be added if `editable-events` option is set to `true` --><divclass="vuecal__event-delete" />
<div class="vuecal__event">
<!-- Will be added if `editable-events` option is set to `true` -->
<div class="vuecal__event-delete" />
Now this is the part you can customize:
<!-- Will be added if a title is set --><divclass="vuecal__event-title" /><!-- or if title is set and `editable-events` option is set to `true` --><divclass="vuecal__event-title vuecal__event-title--edit"contenteditable /><!-- Will be added if `time` option is set to `true` --><divclass="vuecal__event-time" /><!-- Will be added if a content is set --><divclass="vuecal__event-content" />
Now this is the part you can customize:
<!-- Will be added if a title is set -->
<div class="vuecal__event-title" />
<!-- or if title is set and `editable-events` option is set to `true` -->
<div class="vuecal__event-title vuecal__event-title--edit" contenteditable />
<!-- Will be added if `time` option is set to `true` -->
<div class="vuecal__event-time" />
<!-- Will be added if a content is set -->
<div class="vuecal__event-content" />
<!-- Will be added if `editable-events` option is set to `true` --><divclass="vuecal__event-resize-handle" /></div>
<!-- Will be added if `editable-events` option is set to `true` -->
<div class="vuecal__event-resize-handle" />
</div>
Two parameters are passed through the scoped slot:
event: The event full object containing dates, time, title, content and custom attributes.
view: The current selected view id.
You can set any custom attribute you want on an event, they will then be accessible in your custom event renderer!
Note that _eid is a reserved keyword.
47 ( 2018)
19
20
21
22
23
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
shopping_cart
Need to go shopping
Event start:2 O'clock Event end:6 O'clock
golf_course
Golf with John
Event start:10 O'clock Event end:3 O'clock
<vue-calselected-date="2018-11-19":time-from="9 * 60":time-to="19 * 60"hide-weekends:events="events"><template#event="{ event, view }"><v-icon>{{ event.icon }}</v-icon><divclass="vuecal__event-title"v-html="event.title" /><!-- Or if your events are editable: --><divclass="vuecal__event-title vuecal__event-title--edit"contenteditable@blur="event.title = $event.target.innerHTML"v-html="event.title" /><smallclass="vuecal__event-time"><!-- Using Vue Cal Date prototypes (activated by default) --><strong>Event start:</strong><span>{{ event.start.formatTime("h O'clock") }}</span><br/><strong>Event end:</strong><span>{{ event.end.formatTime("h O'clock") }}</span></small></template></vue-cal>
<vue-cal
selected-date="2018-11-19"
:time-from="9 * 60"
:time-to="19 * 60"
hide-weekends
:events="events">
<template #event="{ event, view }">
<v-icon>{{ event.icon }}</v-icon>
<div class="vuecal__event-title" v-html="event.title" />
<!-- Or if your events are editable: -->
<div class="vuecal__event-title vuecal__event-title--edit"
contenteditable
@blur="event.title = $event.target.innerHTML"
v-html="event.title" />
<small class="vuecal__event-time">
<!-- Using Vue Cal Date prototypes (activated by default) -->
<strong>Event start:</strong> <span>{{ event.start.formatTime("h O'clock") }}</span><br/>
<strong>Event end:</strong> <span>{{ event.end.formatTime("h O'clock") }}</span>
</small>
</template>
</vue-cal>
events:[{start:'2018-11-20 14:00',end:'2018-11-20 18:00',title:'Need to go shopping',icon:'shopping_cart',// Custom attribute.
class:'leisure'},{start:'2018-11-22 10:00',end:'2018-11-22 15:00',title:'Golf with John',icon:'golf_course',// Custom attribute.
class:'sport'}]
// In data.
customDaySplitLabels:[{label:'John',color:'blue',class:'split1'},{label:'Tom',color:'green',class:'split2'},{label:'Kate',color:'orange',class:'split3'},{label:'Jess',color:'red',class:'split4'}]
Here is the list of all the parameters available and their description below this table.
Remember that HTML is case-insensitive and you should therefore use the kebab-case
instead of the camelCase for consistency.
activeView:[String],default:'week'allDayBarHeight:[String,Number],default:'25px'cellClickHold:[Boolean],default:truecellContextmenu:[Boolean],default:falseclickToNavigate:[Boolean],default:falsedblclickToNavigate:[Boolean],default:truedisableDatePrototypes:[Boolean],default:falsedisableDays:[Array],default:[]disableViews:[Array],default:[]dragToCreateEvent:[Boolean],default:truedragToCreateThreshold:[Number],default:15editableEvents:[Boolean,Object],default:falseevents:[Array],default:[]eventsCountOnYearView:[Boolean],default:falseeventsOnMonthView:[Boolean,String],default:falsehideBody:[Boolean],default:falsehideTitleBar:[Boolean],default:falsehideViewSelector:[Boolean],default:falsehideWeekdays:[Array],default:[]hideWeekends:[Boolean],default:falselocale:[String],default:'en'maxDate:[String,Date],default:''minCellWidth:[Number],default:0// In pixels.
minDate:[String,Date],default:''minEventWidth:[Number],default:0// In percent.
minSplitWidth:[Number],default:0// In pixels.
onEventClick:[Function],default:nullonEventCreate:[Function],default:nullonEventDblclick:[Function],default:nulloverlapsPerTimeStep:[Boolean],default:falseresizeX:[Boolean],default:falseselectedDate:[String,Date],default:''showAllDayEvents:[Boolean,String],default:falseshowTimeInCells:[Boolean],default:falseshowWeekNumbers:[Boolean,String],default:falsesmall:[Boolean],default:falsesnapToTime:[Number],default:nullspecialHours:[Object],default:{}splitDays:[Array],default:[]startWeekOnSunday:[Boolean],default:falsestickySplitLabels:[Boolean],default:falsetime:[Boolean],default:truetimeCellHeight:[Number],default:40// In pixels.
timeFormat:[String],default:''timeFrom:[Number],default:0// In minutes.
timeStep:[Number],default:60// In minutes.
timeTo:[Number],default:24*60// In minutes.
todayButton:[Boolean],default:falsetransitions:[Boolean],default:truetwelveHour:[Boolean],default:falsexsmall:[Boolean],default:falsewatchRealTime:[Boolean],default:false
Allows you to translate the calendar texts in a given language.
Use a 2 letter locale code
(ISO 639-1)
unless a distinction is needed. E.g. 'pt-br' for Portuguese-Brasilian.
priority_highCurrently available languages are Albanian, Arabic, Bangla, Bosnian, Bulgarian, Catalan, Czech, Chinese (Simplified), Chinese (Traditional), Croatian, Danish, Dutch, English, Estonian, Farsi, French, Georgian, German, Greek, Hebrew, Hungarian, Icelandic, Italian, Indonesian, Japanese, Korean, Lithuanian, Mongolian, Norwegian, Polish, Portuguese Brasilian, Romanian, Russian, Serbian, Slovak, Slovenian, Spanish, Swedish, Turkish, Ukrainian, Vietnamese.
If you are interested in providing a language support please do a pull request with a json file
into the i18n directory.
this is what a language json looks like.
{"weekDays":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"months":["January","February","March","April","May","June","July","August","September","October","November","December"],"years":"Years","year":"Year","month":"Month","week":"Week","day":"Day","today":"Today","noEvent":"No Event","allDay":"All day","deleteEvent":"Delete","createEvent":"Create an event","dateFormat":"dddd D MMMM YYYY"}
Regarding the dateFormat translation, this is the format of the full
date you can see in a single day view title. dddd stands for the full-letter day of week, MMMM stands for
full-letter month, D stands for the date of the month (0-31),
YYYY stands for full year, {S} stands for st/nd/rd/th and only in English.
wb_incandescentNote that 2 media queries will shorten the days of the week to 3 letters then 1 letter when it does not fit.
You can read more about it in the # Responsiveness & Media Queries section in the
CSS Notes.
hideViewSelector[Boolean], default: false
When set to true, the top view selector will disappear.
You can still navigate from a view to another by clicking a cell (narrower view) or
the view title (broader view).
hideTitleBar[Boolean], default: false
When set to true, the title bar with navigating arrows will disappear.
You can still navigate from a view to another with the view selector and clicking
a cell (narrower view).
hideBody[Boolean], default: false
When set to true, the whole calendar body will disappear - cells and timeline.
Also means that all the logic usually triggered from the calendar's body won't run at all.
hideWeekends[Boolean], default: false
Hide the weekend and shows only Monday to Friday on month view and week view.
The weekend are still visible in day view not to break the behavior of the arrows.
Note that by hiding the arrows you won't be able to see a weekend day in day view if hideWeekends
is true.
hideWeekdays[Array], default: []
Hide particular days of the week. This option accepts an array of days (day numbers) to hide,
starting at 1 for Monday, to 7 for Sunday.
This option will apply on month & week views.
If you want to hide Saturday and Sunday you can put 6, 7 in the array or use
hideWeekends in supplement of hideWeekdays.
disableDays[Array], default: []
Allows you to provide an array of formatted dates (e.g. 2020-09-18) to disable.
disableViews[Array], default: []
Allows you to totally disable one or more of the available views.
Accepted view names are 'years', 'year', 'month', 'week', 'day'.
Note that the navigation between views via cells click or title click won't
break and will only navigate to views you have allowed.
dragToCreateEvent[Boolean], default: true
When events are editable and if time and dragToCreateEvent are set to
true, clicking and dragging on a cell will create an event.
Note: if this option is set to true, it will prevent event creation from cell click & hold.
Refer to the Create events example.
dragToCreateThreshold[Number], default: 15
When events are editable and time and dragToCreateEvent are set to
true, this option controls the minimum dragging distance before an event is created.
This option might be useful when you can navigate with cell click to prevent unwanted event creation in
case of slipping cursor while clicking.
With option gets to a positive integer, and you can set it to 0 to disable it.
Refer to the Create events example.
activeView[String], default: 'week'
Allows you to set a default active view, for the first time you load the calendar.
Then control the active view from outside of Vue Cal.
Accepts one of 'years', 'year', 'month', 'week', 'day'.
The active view has a two-way binding: you can use a v-model (or .sync on Vue 2)
on it to keep your variable up to date.
allDayBarHeight[String, Number], default: '25px'
When the all day bar is visible and Vue Cal is also scrollable horizontally (due to
minCellWidth or day splits with minSplitWidth),
the all-day bar must have a fixed height for this particular layout.
Only if these conditions are fulfilled, the height provided through this option will be
used. If none is provided the default height will be used.
The height can be any valid CSS height (as a string) or an integer for an amount of pixels.
todayButton[Boolean], default: false
Adds a Today button in the title bar to quickly go to Today's date.
showAllDayEvents[Boolean, String], default: false
When the showAllDayEvents is set to true the events with an
allDay attribute set to true will be displayed in a fixed top
bar on the week & day views.
The all day events bar will only show up if the options showAllDayEvents &
time are set to true. time is important since without time information every event is an all-day
event there is no point in separating them then.
When showAllDayEvents is set to false, all the all day events
(allDay attribute set to true), will show up as a normal
background event.
On month view, switching showAllDayEvents on and off will not have any impact
since both should display the all day events.
showAllDayEvents accepts a Boolean or the string
'short', to display only the event title.
showWeekNumbers[Boolean], default: false
When set to true, the weeks numbers will show in the first column on the
month view (only).
You can also provide a custom renderer to the weeks numbers cells through the
week-number-cell slot.
priority_highDid you know there can be 53 weeks in the year? This happens every time the year starts a Thursday, or starts a Wednesday of a leap year.
In this case the week number will be 53 instead of 1.
selectedDate[String, Date], default: ''
Accepts a formatted string or plain JS Date object.
Set a selected date, for the first time you load the calendar.
This day will be highlighted and the first view will naturally show this date.
E.g. setting a date in year 2000 with a activeView of week, will show you that week of year 2000.
Updating the selectedDate programmatically after the first calendar load,
will update the view if needed to show this date.
Refer to the Sync two vue-cal instances example.
The selected date has a two-way binding: you can use a v-model (or .sync on Vue 2) on it to
keep your variable up to date.
priority_highA correct string date format is 2025-03-28 22:59 or
2025-03-28 if you don't need the time.
Only these formats will work as a string. You can also provide a native Javascript Date object.
minDate[String, Date], default: ''
Accepts a formatted string or plain JS Date object.
Set a minimum date for the cells to be selectable.
By default the cell will be grayed out when out of range but CSS classes let you customize this.
maxDate[String, Date], default: ''
Accepts a formatted string or plain JS Date object.
Set a maximum date for the cells to be selectable.
By default the cell will be grayed out when out of range but CSS classes let you
customize this.
specialHours[Object], default: {}
Allows an individual highlighted time range for each day of the week.
For instance, it could represent the business hours.
The object must contain indexed days, from 1 for Monday to 7 for Sunday, of the
days you want to highlight.
Each day must contain an object with a from and to properties
defining the beginning and the end of the time range in minutes.
In addition, you can set a CSS class for each day of the week.
It is also possible to provide an array of special hours for the same day.
A label can also be provided per special hour block, and styled via CSS.
Example for Wednesday: :special-hours="specialHours"
With a single range of special hours:
// In the component's data.
specialHours:{3:{from:8*60,to:20*60,class:'open'}}
// In the component's data.
specialHours: {
3: { from: 8 * 60, to: 20 * 60, class: 'open' }
}
With multiple ranges of special hours:
// In the component's data.
specialHours:{3:[{from:8*60,to:12*60,class:'open'},{from:14*60,to:20*60,class:'open'}]}
// In the component's data.
specialHours: {
3: [
{ from: 8 * 60, to: 12 * 60, class: 'open' },
{ from: 14 * 60, to: 20 * 60, class: 'open' }
]
}
startWeekOnSunday[Boolean], default: false
By default weeks start on Monday but with this option you can start the week on Sunday.
small[Boolean], default: false
When set to true, the days of the week headings will be truncated to 3 letters.
Does not apply to the title of the day view.
2 media queries are truncating the days of the week below 450px,
read on in the CSS Notes.
xsmall[Boolean], default: false
When set to true, the days of the week headings will be truncated to 1 letter.
Does not apply to the title of the day view.
In Addition, the whole calendar gets applied a smaller font size of 0.9em,
and the current view title is also reduced.
2 media queries are truncating the days of the week below 450px,
read on in the CSS Notes.
transitions[Boolean], default: true
Enable / disable the CSS transitions between all the views and view states.
clickToNavigate[Boolean], default: false
When set to true a single click (or tap for touch devices) will take you to a
narrower view if available.
You can always go back to a broader view by clicking the view title or selecting another view
from the view selector if enabled.
The navigation to narrower view can be disabled by setting both clickToNavigate
and dblclickToNavigate to false.
dblclickToNavigate[Boolean], default: true
When set to true a double click (or double tap for touch devices) will take you to a
narrower view if available.
You can always go back to a broader view by clicking the view title or selecting another view
from the view selector if enabled.
The navigation to narrower view can be disabled by setting both clickToNavigate
and dblclickToNavigate to false.
cellClickHold[Boolean], default: true
Allows you to disable the default event creation on cell click & hold which only
happens if editableEvents.create is set to true.
cellContextmenu[Boolean], default: false
When set to true, a right click on a cell will emit the cell-contextmenu event,
providing an object containing: the date and time at cursor, the x and y position of cursor, and the full original DOM event.
time[Boolean], default: true
Whether you want to display the timeline and handle events with time or only date.
Note that time is made of hours:minutesand no second.
timeFrom[Number], default: 0
If time is enabled, set the start of the timeline in minutes.
By default it starts at midnight.
showTimeInCells[Boolean], default: false
When set to true, the time labels will be visible in
each cell, in each time slot of the day and week views.
You can then use CSS to style to taste.
For instance, you could hide all the labels and show only the one that
is being hovered.
Will have no effect if time is set to false.
timeTo[Number], default: 24 * 60
If time is enabled, set the end of the timeline in minutes.
By default it ends at 24:00.
timeStep[Number], default: 60
If time is enabled, set the time increment in minutes.
timeCellHeight[Number], default: 40
If time is enabled, set the time cell height in pixels.
this is very important as it is used to calculate the events position in the day.
twelveHour[Boolean], default: false
If time is enabled, the default time format is 24 hour.
With twelveHour set to true (use twelve-hour in template),
the time format will show 12 hours suffixed with am/pm.
timeFormat[String], default: ''
When defined, overrides the default time format in time cells and events.
Formatted time can contain any character but the following characters will be replaced:
H: Hours no leading zero, 24-hour format
HH: Hours with leading zero, 24-hour format
h: Hours no leading zero, 12-hour format
hh: Hours with leading zero, 12-hour format
m: Minutes no leading zero
mm: Minutes with leading zero
{am}: am or pm
The characters `{` and `}` are removed and used only to
delimit keywords when there is no space.
E.g. "h:mm{am}".
watchRealTime[Boolean], default: false
When set to true, the current time line in today's cell, on week and
day views, will stay in sync with real time. (This requires a setTimeout every minute)
minEventWidth[Number], default: 0
When a number is set, in percent, each event within a cell will have a minimum width.
If the provided percentage is bigger than what it would naturally be, the events will partially overlap.
overlapsPerTimeStep[Boolean], default: false
When set to true, each event of the same cell will have a width of
100% / [number of simultaneous events] only if these events are within the same time step.
Refer to this use case.
minCellWidth[Number], default: 0
When a number is set, in pixels, each cell of the week view (only)
will have this minimum width.
If it does not fit in the calendar body, the overflow will be scrollable.
If minSplitWidth is also set, it will override minCellWidth.
minSplitWidth[Number], default: 0
This is for day splits only, and it applies to the
week and day views (only).
When a number is set, in pixels, each split of each cell will have this minimum width.
If it does not fit in the calendar body, the overflow will be scrollable.
If minCellWidth is also set, minSplitWidth will override it on
week view.
splitDays[Array], default: []
Split each day into multiple vertical splits.
Accepts an array of split objects with attributes.
Each split object can have these attributes, they are all optional:
{id:{Integer | String},// All ids must be set if using `hide`.
class:{String},label:{String},hide:{Boolean}// You can toggle the column on and of with this.
}
{
id: {Integer | String}, // All ids must be set if using `hide`.
class: {String},
label: {String},
hide: {Boolean} // You can toggle the column on and of with this.
}
stickySplitLabels[Boolean], default: false
When set to true, the day splits labels will be displayed in the header
instead of in-cell.
editableEvents[Boolean, Object], default: false
When editableEvents is set to true, it allows:
Dragging and dropping events
Resizing events by dragging the handle showing at the bottom of each event if time is set to true,
Deleting events by click and hold an event.
Editing events title
priority_high
You can set more accurately which edition you want to allow by passing an object.
For instance, this object will allow all the above editions except the drag & drop:
You can still force an event to be undeletable or unresizable from the deletable & resizable event attributes.
resizeX[Boolean], default: false
When set to true, allows resizing an event across multiple days.
Resizing on the X axis is only available on week view.
snapToTime[Number], default: 0
Accepts a number of minutes from 0 to 60 to snap a dropped event or an event end time while resizing.
For instance, with a snapToTime of 15 min, an event dropped at a start of 10:05,
will snap to 10:00, and dropped at 10:11 will snap to 10:15.
This option affects event resizing, event drag & dropping, and event drag-creation.
When set to true, the events will also be displayed on month view
(including events from visible out of scope days).
When set to the string 'short', only the event's title will be displayed.
eventsCountOnYearView[Boolean], default: false
When set to true, the events count will also be displayed on years
& year views.
onEventClick[Function], default: null
A callback function to execute when an event is clicked.
this function receives 2 parameters: event, the clicked calendar event,
and e, the associated JavaScript DOM event.
onEventDblclick[Function], default: null
A callback function to execute when an event is double clicked.
this function receives 2 parameters: event, the double clicked calendar event,
and e, the associated JavaScript DOM event.
onEventCreate[Function], default: null
A callback function to execute when an event is created.
This function receives 2 parameters: event, the created event,
and deleteEvent, a function to delete the created event.
You can modify and override the received event and return it to vue-cal.
If this function returns false, the event creation will be cancelled.
events[Array], default: []
Allows you to place events in the calendar.
Accepts an array of event objects.
This is what an event object must look like:
{start:'2018-11-19 12:00',// Required.
end:'2018-11-19 14:00',// Required.
// Instead of formatted dates, you can also provide Javascript Date objects:
// start: new Date(2018, 11 - 1, 19, 12, 0),
// end: new Date(2018, 11 - 1, 19, 14, 0),
title:{String},// Optional.
content:{String},// Optional.
class:{String},// Optional - space-separated css classes.
background:{Boolean}// Optional. (Event type not CSS property)
split:{Number|String}// Optional.
allDay:{Boolean}// Optional.
deletable:false// optional - force undeletable when events are editable.
resizable:false// optional - force unresizable when events are editable.
}
{
start: '2018-11-19 12:00', // Required.
end: '2018-11-19 14:00', // Required.
// Instead of formatted dates, you can also provide Javascript Date objects:
// start: new Date(2018, 11 - 1, 19, 12, 0),
// end: new Date(2018, 11 - 1, 19, 14, 0),
title: {String}, // Optional.
content: {String}, // Optional.
class: {String}, // Optional - space-separated css classes.
background: {Boolean} // Optional. (Event type not CSS property)
split: {Number|String} // Optional.
allDay: {Boolean} // Optional.
deletable: false // optional - force undeletable when events are editable.
resizable: false // optional - force unresizable when events are editable.
}
If no title is provided, no title will be displayed.
content accepts free HTML, for instance:
'<i class="icon material-icons">local_hospital</i>'.
If no content is provided, no content will be displayed.
You may need an event CSS class to handle different event types
for instance. With different classes you can apply different styles to the events.
E.g. backgrounds, images, borders, etc.
The background attribute sets an event as a background event,
which allows overlapping and disable the ability to drag & resize.
When using splitDays, the split attribute accepts a number,
starting from 1, corresponding to the split you want the event to appear in.
Optionally, if you have set the id property in splitDays,
you have to use the same id here (Integer or String).
When the showAllDayEvents and time options are set to
true, all the events with an attribute allDay set to
true will show up in a fixed bar (week & day views).
priority_highImportant notes
The events are internally identified by the key `_eid`.
This is a reserved keyword.
Correct date formats are 2025-03-28 22:59,
or 2025-03-28 if you don't want any time in the whole calendar,
or a JavaScript Date object. Only these formats will work. You can't mix events with time and events without, and you can only remove time if the time
option is set to false.
You can set an event end at 24:00 or 00:00 (for the next midnight),
but internally the date will be set at 23:59:59 so the date stays the same instead
of natural behavior of taking the next day at 00:00:00.
When returned from emitted events, this event end will contain a date ending at 23:59:59.
disableDatePrototypes[Boolean], default: false
If you really don't want the Date prototypes to be added, you can disable them with this option.
Refer to This Vue Cal issue on Github.
Vue Cal has no dependency and performs date operations through a few notable useful and efficient functions that
have been added to the native Date class for your convenience. With this set of functions, you will most likely not need Moment.js or any other additional Date library!
Once Vue Cal is loaded, you can access the following functions from anywhere in your code
just like a simple Date function. E.g. (new Date()).addDays(2)
.addDays(days)Adds days to a Date object and returns it. The original Date stays untouched as a copy is made.
`days` is an integer.
.subtractDays(days)Subtracts days to a Date object and returns it. The original Date stays untouched as a copy is made.
`days` is an integer.
.addHours(hours)Adds hours to a Date object and returns it. The original Date stays untouched as a copy is made.
`hours` is an integer.
.subtractHours(hours)Subtracts hours to a Date object and returns it. The original Date stays untouched as a copy is made.
`hours` is an integer.
.addMinutes(minutes)Adds minutes to a Date object and returns it. The original Date stays untouched as a copy is made.
`minutes` is an integer.
.subtractMinutes(minutes)Subtracts minutes to a Date object and returns it. The original Date stays untouched as a copy is made.
`minutes` is an integer.
.getWeek()Returns the week number (1 to 53) of a date.
.isToday()Returns true if the date is Today.
.isLeapYear()Returns true if the date is in a leap year.
And because everyone needs a Date/time formatting function...
It is now available directly from the Date object, with your loaded locale!
.format(format)
Returns a formatted date string.
Default format is 'YYYY-MM-DD', but you can use any formatting keyword from
this list, and add any character not present in this mapping:
YYYY: full year. // `2019`
YY: 2 last digits of the year. // `19`
MMMM: month in full. // `January`
MMM: 3 first letters of the month. // `Jan`
MM: month number with leading zero. (01-12) // `01`
M: month number without leading zero. (1-12) // `1`
DD: date of the month with leading zero. (01-31) // `01`
D: date of the month without leading zero. (1-31) // `1`
S: (usually with surrounding `{ }`) only in English,
will output `st`, `nd`, `rd` or `th`.
dddd: day of the week in full. // `Monday`
ddd: 3 first letters of the day of the week. // `Mon`
dd: first letter of the day of the week. // `M`
d: number of the day of the week. (1-7) // `1` for Monday
And also all the keywords from the following formatTime() function.
.formatTime(format)
Returns a formatted time string.
The format() function can also do this, but this might be a shortcut if you just want
the default time formatting.
E.g. `formatTime()`).
This function will also be slightly faster than format() as lighter in functionality.
Default format is 'HH:mm', but you can use any formatting keyword from
this list, and add any character not present in this mapping:
HH: Hours with leading zero, 24-hour format. (00-24)// `20`
H: Hours without leading zero, 24-hour format. (0-24)// `20`
hh: Hours with leading zero, 12-hour format. // `08`
h: Hours without leading zero, 12-hour format. // `8`
mm: Minutes with leading zero. // `08`
m: Minutes without leading zero. // `8`
am: (usually with surrounding `{ }`) am or pm (also localized if any)
wb_incandescent
To separate 2 keywords or a keyword and another text not from this list without adding spaces or
any separation, you can use the delimiters `{ }`.
For instance `new Date().format('YYYY{MM}DD')` (or even `{YYYY}{MM}{DD}`) will produce:
"20250328".
The Date functions are added when Vue Cal loads, you can always check if you have it before you use it: Date.prototype.format && new Date().format()
If you really don't want the Date prototypes to be added, you can disable them with this option:
disable-date-prototypes.
Refer to This Vue Cal issue on Github.
You can easily change the calendar design with CSS.
# Color themes & rounded theme
Currently 2 color themes (green & blue) are available, in addition to the standard grey theme.
You can apply a green or blue theme by using the CSS class vuecal--green-theme
or vuecal--blue-theme.
If you want another color theme, you can define your own easily.
This is what a standard color theme looks like.
You can copy and change any color to quickly get a nice render.
If that is still not doing what you want you can change even more in your own CSS.
/* Green-theme. */
.vuecal__menu, .vuecal__cell-events-count {background-color:#42b983;}
.vuecal__title-bar {background-color:#e4f5ef;}
.vuecal__cell--today, .vuecal__cell--current {background-color:rgba(240, 240, 255, 0.4);}
.vuecal:not(.vuecal--day-view) .vuecal__cell--selected {background-color:rgba(235, 255, 245, 0.4);}
.vuecal__cell--selected:before {border-color:rgba(66, 185, 131, 0.5);}/* Cells and buttons get highlighted when an event is dragged over it. */
.vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal__cell-split--highlighted {background-color:rgba(195, 255, 225, 0.5);}
.vuecal__arrow.vuecal__arrow--highlighted,
.vuecal__view-btn.vuecal__view-btn--highlighted {background-color:rgba(136, 236, 191, 0.25);}
/* Green-theme. */
.vuecal__menu, .vuecal__cell-events-count {background-color: #42b983;}
.vuecal__title-bar {background-color: #e4f5ef;}
.vuecal__cell--today, .vuecal__cell--current {background-color: rgba(240, 240, 255, 0.4);}
.vuecal:not(.vuecal--day-view) .vuecal__cell--selected {background-color: rgba(235, 255, 245, 0.4);}
.vuecal__cell--selected:before {border-color: rgba(66, 185, 131, 0.5);}
/* Cells and buttons get highlighted when an event is dragged over it. */
.vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal__cell-split--highlighted {background-color: rgba(195, 255, 225, 0.5);}
.vuecal__arrow.vuecal__arrow--highlighted,
.vuecal__view-btn.vuecal__view-btn--highlighted {background-color: rgba(136, 236, 191, 0.25);}
Rounded theme You can use the rounded cells theme like in the Example
Calendar themes - Rounded cells,
by applying the CSS class vuecal--rounded-theme to the Vue Cal wrapper.
# Responsiveness & media queries
This calendar is fully responsive.
To help you in making the calendar always look perfect,
2 media queries (to keep it simple) are in place for small screens.
The media queries operate downwards from 550px & 450px, to truncate the text
of the days of the week from full day name to 3 letters and to 1 letter according to the available space.
If this is not enough for your particular use, you can add your own in your CSS.
Additionally, you can use the options small & xsmall
to truncate week days at any size.
# Disabled text selection
Notice that on Windows machines, and on devices where the scrollbar takes some space and
pushes the calendar main content (week and day views), the
weekdays headings and the all-day bar get an added padding right to align well with the main content.
This is done once, in the mounted hook.
# Disabled text selection
By default the selection is disabled in the whole calendar except in the events.
you can override this by CSS.
Version 4.10.0Merged PRs #585, #536, #528: fixed week start date when starting week on Sunday, fixed maxTimestamp, fixed date format on `en` locale.
Version 4.9.0Added the Portuguese (Portugal) and Finnish locale.
Version 4.8.0Added the Estonian locale.
Version 4.6.0Skip the hidden days on day view (days listed in hideWeekends
and hideWeekdays).
Version 4.5.1Fix wrong starting day on week view when the week starts on sunday
& hideWeekends is true.
Version 4.5.0Added option to display time labels in cells.
Version 4.4.3Fix headings misalignments on certain views, when OS sets fixed scrollbars.
Version 4.4.0Added a v-model on the selected-date.
Version 4.3.4New ESM build by default.
Version 4.0.0Supports and only works on Vue 3.
Version 3.10.1Prevent focusing cells when they are disabled.
Version 3.10.0Allow multiple ranges in daily special hours.
Version 3.9.1Fix: Prevent disabling full month or year when using disable-days.
Version 3.9.0Allow full custom locale.
Version 3.8.4Fix showing events ending at 24:00 on Safari.
Version 3.8.3Return the full original DOM event from cell-contextmenu.
Version 3.8.2Add active-view validations and raise warning if incorrect.
Version 3.8.1Fix all-day events when no time information is provided.
Version 3.8.0Add Mongolian language.
Version 3.7.0Add a new disable-days option.
Version 3.6.5Call the on-event-click function (if any) on event single tap. Also add a 30px threshold to not call the handler if the event was tapped and dragged.
Version 3.6.4
Fix events ending at 00:00, now ends at 23.59.59 of the previous day or of the same day if time is false.
When time is true, keep 23:59:59 internally, but format string to 24:00.
Fix previous / next navigation on day view when date prototypes are disabled.
Add shortWeekDays to the uk locale.
Version 3.6.3Return the correct event on out-of-scope event click on month view.
Version 3.6.2Fix all-day events not showing up and fix error when using hide-body.
Version 3.6.1Fix timeless events not showing up.
Version 3.6.0Added Albanian language and short days in Russian language
Version 3.5.6Fix multiple day events display across days when time is false
Version 3.5.4Add mouseup event listener when deletable but not resizable
Version 3.5.3
Provide the split (if any) to event creation from cell click & hold.
Add mousemove & mouseup event handlers if drag-creation is allowed but
editableEvents.resize is set to false.
Version 3.5.1
Don't fire cell-click when clicking on an event
Focus and highlight cell on mousedown rather than click
Version 3.5.0 Create events with click & drag.
Refer to the Create events example.
Version 3.4.1 Also return the original event from the emitted
event-duration-change event
Version 3.4.0 Add a split-label slot for day splits labels.
Refer to the Custom day split labels example.
Version 3.3.1 Add custom event renderer back in all-day bar events
Version 3.3.0 Added the allDayBarHeight option and fix the all-day
bar layout when using minCellWidth or day splits & minSplitWidth
Version 3.2.8 Call onEventClick() (if any) on event click if events
are not editable or on event creation
Version 3.2.7 Don't call onEventClick() (if any) on event click & hold
Version 3.2.6 Display the no-event slot accurately per slot if there are
Version 3.2.5 Fix emitting view-change between week
& day views
Version 3.2.4 Prevent calling onEventClick after event resize & focus event on resize
Version 3.2The new two way binding active-view prop replaces the default-view prop.
Refer to the external controls example.
Version 3.1.1 Allow disabling event titleEditable individually
Version 3.1.0
priority_highThe event properties startDate and endDate have been merged into
start and end which now accept both a String and a Javascript Date. Vue Cal always returns the Date object and not the string, even if you defined it as a string,
but Vue Cal offers Date prototype functions to easily format the date how you want.
Fixed multiple day events resizing on x and y axis.
Allow disabling Date prototypes
Emit an event-resizing repeatedly while resizing an event
Version 3.0
The arrival of the drag & drop feature marks a new milestone for Vue Cal!
Many subsequent features to come, progressively building the most intuitive full-featured and flexible calendar
on Vue.js, 100% designed for Vue, and still no dependency!
priority_high
Like the native HTML5 drag & drop it's built with, Vue Cal's drag & drop is not
available on touch screens
Vue Cal will support touch screen drag & drop later on, using an alternative technology.
check
New Features
Events drag & drop
Drag & drop is a module (to keep Vue Cal light weight) and must be loaded
separately: import 'vue-cal/dist/drag-and-drop.js'
Drop an external (HTML5 draggable) event into Vue Cal or between 2 Vue Cal instances
snapToTime option on event drop and event resize
Refer to the snapToTime option in the API section.
The editableEvents option now also accept an object to precisely allow specific edition
Refer to the editableEvents option in the API section.
Big changes
In the coming version 3.1:
Now that Vue Cal has Date prototypes and it is so easy to format a date,
the event properties startDate and endDate will be removed
and the start and end of event will be exlusively defined through start
and end. It will accept both a String and a Javascript Date.
Vue Cal will always return the Date object and not the string, even if you defined it
as a string.
The event-change emitted event now returns an object containing the
event and the originalEvent.
the event-title-change and event-duration-change events now return an object
containing the event and the oldTitle or oldDate.
Vue Cal's createEvent() function now accepts a duration parameter to easily override
the default 2 hours.
(ref. Create events example)
The internal event classes property is replaced with
class like in the external event definition. This means you can now
update the class property seemlessly like the initial event definition.
(From your component methods called from Vue Cal fired events or from onEventCreate)
Renamed slot
The event-renderer slot is renamed into event
Huge code refactoring
Introducing Vue dependency injections, Utils classes, and a couple of improvements on
event resize.
Other noticeable changes
When creating an event with a given endDate, the required
endTimeMinutes is automatically add.
You don't need to call alignAllDayBar() anymore
Previously, in some cases you would need to call this function to realign the
all-day bar with the scrollbar when the scrollbar is fixed (E.g. on Windows).
Now the function (renamed to alignWithScrollbar) is triggered automatically
and in all the cases, once, in mounted.
It will now also align the weekdays headings if needed.
Renamed CSS classes
If you use them in your own CSS (or if you have a custom color theme)
you might want to update them:
Cells
.current becomes .vuecal__cell--current
.today becomes .vuecal__cell--today
.out-of-scope becomes .vuecal__cell--out-of-scope
.before-min becomes .vuecal__cell--before-min
.after-max becomes .vuecal__cell--after-max
.disabled becomes .vuecal__cell--disabled
.selected becomes .vuecal__cell--selected
.vuecal__cell--has-splits & .vuecal__cell--has-events remain the same
View selector buttons
Added class: .vuecal__view-btn
.active becomes .vuecal__view-btn--active
New CSS classes when an event is dragged
Over a cell: .vuecal__cell--highlighted
Over a menu arrow (previous & next): .vuecal__arrow--highlighted
Over a menu view button: .vuecal__view-btn--highlighted
Event dragging class: .vuecal__event-dragging
Updated color theme
If you have a custom color theme, these new classes should be added:
.vuecal__view-btn--highlighted,
.vuecal__arrow--highlighted,
.vuecal__cell--highlighted.
Refer to the CSS Notes.