React Native Calendars 🗓️ 📆
This module includes various customizable React-Native calendar components.
The package is both Android and iOS compatible.
See our new Docs site
Try it out
You can run example module by performing these steps:
$ git clone git@github.com:wix/react-native-calendars.git
$ cd react-native-calendars
$ npm install
$ cd ios && pod install && cd ..
$ react-native run-ios
You can check example screens source code in example module screens
This project is compatible with Expo/CRNA (without ejecting), and the examples have been published on Expo
Installation
$ npm install --save react-native-calendars
The solution is implemented in JavaScript so no native module linking is required.
Usage
import {
Calendar, CalendarList, Agenda} from 'react-native-calendars';
All parameters for components are optional. By default the month of current local date will be displayed.
Event handler callbacks are called with calendar objects
like this:
{
day: 1,
month: 1,
year: 2017,
timestamp,
dateString: '2016-05-13'
}
Parameters that require date types accept YYYY-MM-DD
formatted date-strings
, JavaScript date objects, calendar objects
and UTC timestamps
.
Calendars can be localized by adding custom locales to LocaleConfig
object:
import {LocaleConfig} from 'react-native-calendars';
LocaleConfig.locales['fr'] = {
monthNames: [
'Janvier',
'Février',
'Mars',
'Avril',
'Mai',
'Juin',
'Juillet',
'Août',
'Septembre',
'Octobre',
'Novembre',
'Décembre'
],
monthNamesShort: ['Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.'],
dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
dayNamesShort: ['Dim.', 'Lun.', 'Mar.', 'Mer.', 'Jeu.', 'Ven.', 'Sam.'],
today: "Aujourd'hui"
};
LocaleConfig.defaultLocale = 'fr';
Calendar
Basic parameters
<Calendar
initialDate={'2012-03-01'}
minDate={'2012-05-10'}
maxDate={'2012-05-30'}
onDayPress={day => {
console.log('selected day', day);
}}
onDayLongPress={day => {
console.log('selected day', day);
}}
monthFormat={'yyyy MM'}
onMonthChange={month => {
console.log('month changed', month);
}}
hideArrows={true}
renderArrow={direction => <Arrow />}
hideExtraDays={true}
disableMonthChange={true}
firstDay={1}
hideDayNames={true}
showWeekNumbers={true}
onPressArrowLeft={subtractMonth => subtractMonth()}
onPressArrowRight={addMonth => addMonth()}
disableArrowLeft={true}
disableArrowRight={true}
disableAllTouchEventsForDisabledDays={true}
renderHeader={date => {
}}
enableSwipeMonths={true}
/>
Date marking
Disclaimer: Make sure that markedDates
param is immutable. If you change markedDates
object content but the reference to it does not change calendar update will not be triggered.
Dot marking
<Calendar
markedDates={{
'2012-05-16': {selected: true, marked: true, selectedColor: 'blue'},
'2012-05-17': {marked: true},
'2012-05-18': {marked: true, dotColor: 'red', activeOpacity: 0},
'2012-05-19': {disabled: true, disableTouchEvent: true}
}}
/>
You can customize a dot color for each day independently.
Multi-Dot marking
Use markingType={'multi-dot'}
if you want to display more than one dot. Both the <Calendar/>
and <CalendarList/>
support multiple dots by using dots
array in markedDates
prop.
The property color
is mandatory while key
and selectedColor
are optional. If key is omitted then the array index is used as key. If selectedColor
is omitted then color
will be used for selected dates.
const vacation = {key: 'vacation', color: 'red', selectedDotColor: 'blue'};
const massage = {key: 'massage', color: 'blue', selectedDotColor: 'blue'};
const workout = {key: 'workout', color: 'green'};
<Calendar
markingType={'multi-dot'}
markedDates={{
'2017-10-25': {dots: [vacation, massage, workout], selected: true, selectedColor: 'red'},
'2017-10-26': {dots: [massage, workout], disabled: true}
}}
/>;
Period marking
<Calendar
markingType={'period'}
markedDates={{
'2012-05-20': {textColor: 'green'},
'2012-05-22': {startingDay: true, color: 'green'},
'2012-05-23': {selected: true, endingDay: true, color: 'green', textColor: 'gray'},
'2012-05-04': {disabled: true, startingDay: true, color: 'green', endingDay: true}
}}
/>
Multi-period marking
CAUTION: This marking is only fully supported by the <Calendar/>
component because it expands its height. Usage with <CalendarList/>
might lead to overflow issues.
<Calendar
markingType="multi-period"
markedDates={{
'2017-12-14': {
periods: [
{startingDay: false, endingDay: true, color: '#5f9ea0'},
{startingDay: false, endingDay: true, color: '#ffa500'},
{startingDay: true, endingDay: false, color: '#f0e68c'}
]
},
'2017-12-15': {
periods: [
{startingDay: true, endingDay: false, color: '#ffa500'},
{color: 'transparent'},
{startingDay: false, endingDay: false, color: '#f0e68c'}
]
}
}}
/>
Custom marking allows you to customize each marker with custom styles.
<Calendar
markingType={'custom'}
markedDates={{
'2018-03-28': {
customStyles: {
container: {
backgroundColor: 'green'
},
text: {
color: 'black',
fontWeight: 'bold'
}
}
},
'2018-03-29': {
customStyles: {
container: {
backgroundColor: 'white',
elevation: 2
},
text: {
color: 'blue'
}
}
}
}}
/>
NEW! While we still don't support multi marking type, we add the possibility to combine between period
and simple
.
<Calendar
markingType={'period'}
markedDates={{
'2012-05-15': {marked: true, dotColor: '#50cebb'},
'2012-05-16': {marked: true, dotColor: '#50cebb'},
'2012-05-21': {startingDay: true, color: '#50cebb', textColor: 'white'},
'2012-05-22': {color: '#70d7c7', textColor: 'white'},
'2012-05-23': {color: '#70d7c7', textColor: 'white', marked: true, dotColor: 'white'},
'2012-05-24': {color: '#70d7c7', textColor: 'white'},
'2012-05-25': {endingDay: true, color: '#50cebb', textColor: 'white'}
}}
/>
Keep in mind that different marking types are not compatible. You can use just one marking style for a calendar.
Displaying data loading indicator
The loading indicator next to the month name will be displayed if <Calendar/>
has displayLoadingIndicator
prop and the markedDates
collection does not have a value for every day of the month in question. When you load data for days, just set []
or special marking value to all days in markedDates
collection.
Customizing look & feel
<Calendar
style={{
borderWidth: 1,
borderColor: 'gray',
height: 350
}}
theme={{
backgroundColor: '#ffffff',
calendarBackground: '#ffffff',
textSectionTitleColor: '#b6c1cd',
textSectionTitleDisabledColor: '#d9e1e8',
selectedDayBackgroundColor: '#00adf5',
selectedDayTextColor: '#ffffff',
todayTextColor: '#00adf5',
dayTextColor: '#2d4150',
textDisabledColor: '#d9e1e8',
dotColor: '#00adf5',
selectedDotColor: '#ffffff',
arrowColor: 'orange',
disabledArrowColor: '#d9e1e8',
monthTextColor: 'blue',
indicatorColor: 'blue',
textDayFontFamily: 'monospace',
textMonthFontFamily: 'monospace',
textDayHeaderFontFamily: 'monospace',
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16
}}
/>
Customize days titles with disabled styling
<Calendar
theme={{
textSectionTitleDisabledColor: '#d9e1e8'
}}
markedDates={{
...this.getDisabledDates('2012-05-01', '2012-05-30', [0, 6])
}}
disabledDaysIndexes={[0, 6]}
/>
Advanced styling
If you want to have complete control over the calendar styles you can do it by overriding default style.ts
files. For example, if you want to override <CalendarHeader/>
style first you have to find stylesheet id for this file:
https://github.com/wix/react-native-calendars/blob/master/src/calendar/header/style.ts#L60
In this case it is stylesheet.calendar.header
. Next you can add overriding stylesheet to your theme with this id.
https://github.com/wix/react-native-calendars/blob/master/example/src/screens/calendars.tsx#L142
theme={{
arrowColor: 'white',
'stylesheet.calendar.header': {
week: {
marginTop: 5,
flexDirection: 'row',
justifyContent: 'space-between'
}
}
}}
Using the above advanced styling, it is possible to set styles independently for each day's header. If we wanted to make the header for Sunday red, and Saturday blue, we could write something like the following:
theme={{
'stylesheet.calendar.header': {
dayTextAtIndex0: {
color: 'red'
},
dayTextAtIndex6: {
color: 'blue'
}
}
}}
Disclaimer: Issues that arise because something breaks after using stylesheet override will not be supported. Use this option at your own risk.
Overriding day component
If you need custom functionality not supported by current day component implementations you can pass your own custom day component to the calendar.
<Calendar
style={[styles.calendar, {height: 300}]}
dayComponent={({date, state}) => {
return (
<View>
<Text style={{textAlign: 'center', color: state === 'disabled' ? 'gray' : 'black'}}>{date.day}</Text>
</View>
);
}}
/>
The dayComponent
prop has to receive a RN component or a function that receive props. The dayComponent
will receive such props:
- state - disabled if the day should be disabled (this is decided by base calendar component).
- marking -
markedDates
value for this day. - date - the date object representing this day.
Tip: Don't forget to implement shouldComponentUpdate()
for your custom day component to make the calendar perform better
If you implement an awesome day component please make a PR so that other people could use it :)
CalendarList
<CalendarList/>
is scrollable semi-infinite calendar composed of <Calendar/>
components. Currently it is possible to scroll 4 years back and 4 years to the future. All parameters that are available for <Calendar/>
are also available for this component. There are also some additional params that can be used:
<CalendarList
onVisibleMonthsChange={(months) => {console.log('now these months are visible', months);}}
pastScrollRange={50}
futureScrollRange={50}
scrollEnabled={true}
showScrollIndicator={true}
...calendarParams
/>
Horizontal CalendarList
You can also make the CalendarList
scroll horizontally. To do that you need to pass specific props to the CalendarList
:
<CalendarList
horizontal={true}
pagingEnabled={true}
calendarWidth={320}
...calendarListParams
...calendarParams
/>
Agenda
An advanced Agenda
component that can display interactive listings for calendar day items.
<Agenda
items={{
'2012-05-22': [{name: 'item 1 - any js object'}],
'2012-05-23': [{name: 'item 2 - any js object', height: 80}],
'2012-05-24': [],
'2012-05-25': [{name: 'item 3 - any js object'}, {name: 'any js object'}]
}}
loadItemsForMonth={month => {
console.log('trigger items loading');
}}
onCalendarToggled={calendarOpened => {
console.log(calendarOpened);
}}
onDayPress={day => {
console.log('day pressed');
}}
onDayChange={day => {
console.log('day changed');
}}
selected={'2012-05-16'}
minDate={'2012-05-10'}
maxDate={'2012-05-30'}
pastScrollRange={50}
futureScrollRange={50}
renderItem={(item, firstItemInDay) => {
return <View />;
}}
renderDay={(day, item) => {
return <View />;
}}
renderEmptyDate={() => {
return <View />;
}}
renderKnob={() => {
return <View />;
}}
renderEmptyData={() => {
return <View />;
}}
rowHasChanged={(r1, r2) => {
return r1.text !== r2.text;
}}
hideKnob={true}
showClosingKnob={false}
markedDates={{
'2012-05-16': {selected: true, marked: true},
'2012-05-17': {marked: true},
'2012-05-18': {disabled: true}
}}
disabledByDefault={true}
onRefresh={() => console.log('refreshing...')}
refreshing={false}
refreshControl={null}
theme={{
...calendarTheme,
agendaDayTextColor: 'yellow',
agendaDayNumColor: 'green',
agendaTodayColor: 'red',
agendaKnobColor: 'blue'
}}
style={{}}
/>
Authors
See also the list of contributors who participated in this project.
Contributing
Pull requests are most welcome!
Please npm run test
and npm run lint
before push.
Don't forget to add a title and a description that explain the issue you're trying to solve and your suggested solution.
Screenshots and gifs are VERY helpful.
Please do NOT format the files as we are trying to keep a unified syntax and the reviewing process fast and simple.