Mobile app developers use various GUI elements in their apps, like buttons, lists, input boxes, and text regions within app screens. Sometimes, we need complex GUI elements, such as calendars, timetables, agenda views, etc.
The React Native framework offers inbuilt components for adding primary GUI elements, but for designing complex GUI components, we’ll have to either build them from scratch with inbuilt core elements or reuse pre-implemented components from third-party libraries.
The react-native-calendars
library offers pre-implemented, customizable components for adding calendars to your React Native apps. You can use these calendar components for creating customized shareable calendars to display date-based data and capture date values from the user.
In this tutorial, I will explain how to create customized shareable calendars with react-native-calendars
, and let you know about several alternative packages for creating customizable calendars.
Jump ahead:
- Highlighted features of
react-native-calendars
react-native-calendars
tutorial- Supported calendar UI customizations
- Customizing the calendar theme
- Using the
Agenda
component for advanced use cases - How to place calendar components
react-native-calendars
componentsreact-native-calendars
alternatives
Highlighted features of react-native-calendars
This calendar library offers the following highlighted features for adding customizable high-quality calendar components:
Multiple components for your needs
The library offers various components for creating calendars, agenda views, and timelines. Here are the popular ones for creating calendars:
Calendar
: Renders a calendar component with inbuilt month navigation supportCalendarList
: A modern, stylish component that renders a semi-infinite, scrollable calendar listAgenda
: A complex calendar component helps developers implement timetables, appointment tables, and date schedulers
Cross-platform support and consistent look and feel
Cross-platform support is indeed a crucial fact to consider while selecting React Native libraries. This package officially supports Android and iOS platforms and offers a consistent look and feel with primary React Native components (Text
, TouchableOpacity
, etc.) that look almost the same on both operating systems.
Extensive customizations and features
Each library component exposes several props to customize the particular component’s behavior and features. For example, this package lets you customize the calendar component’s fonts and colors by providing a theme object. Also, you can mark individual dates and date ranges with inbuilt customizable indicators and custom shapes.
It’s possible to achieve advanced styling customizations by overriding stylesheet definitions. So, if you use your own theme for your app, using the existing theme colors is easy. This package also lets you attach callbacks for various events, so building a customized, modern date picker is feasible.
react-native-calendars tutorial
Now, we already know an overview of the calendars package. Let’s start using it practically in a React Native app to become more familiar by testing its features. You can use the upcoming code examples directly in an existing app or create a new experimental app to continue with the tutorial.
If you would like to get started with a new project, create one with the following command:
npx react-native init CalendarsExample cd CalendarsExample
Next, run the app to make sure that everything works fine:
npx react-native run-android # --- or --- npx react-native run-ios
Enter the following command and install react-native-calendars
:
npm install react-native-calendars # --- or --- yarn install react-native-calendars
Let’s start with the Calendar
component and learn its customizations and features in depth!
Creating a basic calendar
The Calendar
component lets you render a traditional calendar element that supports month navigation. There are no mandatory props here — use the component with no props in App.js
to create a calendar with the default setup:
import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, } from 'react-native'; import { Calendar } from 'react-native-calendars'; function App() { return ( <SafeAreaView style={styles.container}> <Calendar /> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' }, }); export default App;
The above code will render a calendar component with default features and styles, as shown in the following preview:

Note: Selecting a date won’t render a highlighted background style as everyone expects as an inbuilt feature — we’ll have to write some code for it. I will explain how to highlight the selected date in the Marking individual days section.
Attaching touch event callbacks
The calendar component is interactive, so users can perform actions by pressing the month navigation arrows and day elements.
This library exposes several props to attach callbacks for these crucial user actions. Look at the following sample callback implementations:
<Calendar onDayPress={(day) => console.log('onDayPress', day) } onDayLongPress={(day) => console.log('onDayLongPress', day) } onMonthChange={(date) => console.log('onMonthChange', date) } onPressArrowLeft={(goToPreviousMonth) => { console.log('onPressArrowLeft'); goToPreviousMonth(); }} onPressArrowRight={(goToNextMonth) => { console.log('onPressArrowRight'); goToNextMonth(); }} />
Handlers are executed on the following inputs:
onDayPress
: When the user taps a specific day elementonDayLongPress
: When the user long presses a day elementonMonthChange
: When the calendar month changesonPressArrowLeft
: When the user clicks the left-side month navigation arrowonPressArrowRight
: When the user clicks the right-side month navigation arrow
Run the above code snippet, inspect the code, modify it, and become familiar with all our callbacks. For example, you can get the user-pressed date as follows:
onDayPress={(day) => console.log('Selected date: ', day.dateString) }
Experiment with all the other callbacks by attaching function implementations.
Setting initial, min, and max dates
In some scenarios, using a default calendar with callback implementations is not enough to satisfy app specifications. Sometimes, we need to set the initially selected month and minimum/maximum end date. The Calendar
component offers props to set initial, min, and max dates.
Assume that you need to make a calendar component that initially shows December 2022 and lets you press only a day between the 1st of December 2022 and the 30th of January 2023. The following code snippet satisfies this specification:
<Calendar initialDate="2022-12-01" minDate="2022-12-01" maxDate="2023-01-30" disableAllTouchEventsForDisabledDays={true} />
Here, the disableAllTouchEventsForDisabledDays
boolean prop helps us disable the touch feedback for disabled date elements. Run the app code snippet and compare the result with the above specification:

Making the calendar component reusable
If you need to use the above calendar in several places, creating a reusable component is undoubtedly a good practice:
import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, } from 'react-native'; import { Calendar } from 'react-native-calendars'; function CustomCalendar(props) { return ( <Calendar initialDate="2022-12-01" minDate="2022-12-01" maxDate="2023-01-30" disableAllTouchEventsForDisabledDays={true} {...props} /> ); } function App() { return ( <SafeAreaView style={styles.container}> <CustomCalendar onDayPress={(day) => console.log(`Date pressed: ${day.dateString}`)} /> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, }); export default App;
The above CustomCalendar
component uses custom initial, min, and max dates. It also accepts Calendar
props for further customizations. We’ll discuss how to develop a reusable date picker component in an upcoming section — then, you can learn more about creating shareable calendars.
Supported calendar UI customizations
The calendar component consists of View
, TouchableOpacity
, and Text
-like inbuilt framework components, unlike the platform-specific, native date picker component in Android and iOS. So, it offers numerous props for extensive UI customization.
For example, you can disable the left and right arrows with the disableLeftArrow
and disableRightArrow
boolean props in the previous CustomCalendar
implementation:
function CustomCalendar(props) { return ( <Calendar initialDate="2022-12-01" minDate="2022-12-01" maxDate="2022-12-31" disableAllTouchEventsForDisabledDays={true} disableArrowLeft={true} disableArrowRight={true} {...props} /> ); }
Now, you will only see December 2022, since month-by-month navigation is not possible:

Hiding both arrows is also possible with the hideArrows
boolean prop:
function CustomCalendar(props) { return ( <Calendar initialDate="2022-12-01" minDate="2022-12-01" maxDate="2022-12-31" disableAllTouchEventsForDisabledDays={true} hideArrows={true} {...props} /> ); }
By default, week rows start with Sunday. You can start every week row with Monday and show week numbers on the calendar with the following props:
firstDay={1} showWeekNumbers={true}
Look at the following preview:

Using a custom month format is also possible with the dateFormat
prop. For example, the following setup will render Dec/2020
-like month strings:
monthFormat="MMM/yyyy"
Browse the official documentation and identify all supported calendar props that help customizing the calendar UI.
Marking individual days
Look at a physical paper calendar on your table or wall. You will see that several day boxes are marked with background colors or symbols to indicate special days or national holidays. How can we mark day elements in the Calendar
component similar to the physical one?
The Calendar
component lets you mark dates via the markedDates
prop. Let’s learn how to mark individual days first! Use the following code for CustomCalendar
:
function CustomCalendar(props) { const marked = { '2022-12-10': { marked: true }, '2022-12-12': { selected: true } }; return ( <Calendar initialDate="2022-12-01" minDate="2022-12-01" maxDate="2022-12-31" disableAllTouchEventsForDisabledDays={true} markedDates={marked} {...props} /> ); }
If the marked
boolean prop is set to true
, the component will render a dot on a specific day; if the selected
boolean prop is set to true
, the component will render a filled circle around the particular day element. Look at the following preview:

It’s possible to customize the above indicators and shapes as follows:
const marked = { '2022-12-10': { marked: true, dotColor: 'red' }, '2022-12-12': { selected: true, selectedColor: '#aa2222', selectedTextColor: 'yellow' }, '2022-12-13': { marked: true, selected: true, selectedColor: '#222222', selectedTextColor: 'yellow', dotColor: 'white' } };
Once you use the above definition for marked
, you will see the following result:

The markedDates
prop helps us to mark the currently pressed day element with a simple implementation. We can store the current date in the component state and update the markedDates
object accordingly, as shown in the following code:
import React, { useState, useMemo } from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, } from 'react-native'; import { Calendar } from 'react-native-calendars'; function CustomCalendar(props) { const initDate = '2022-12-01'; const [selected, setSelected] = useState(initDate); const marked = useMemo(() => ({ [selected]: { selected: true, selectedColor: '#222222', selectedTextColor: 'yellow', } }), [selected]); return ( <Calendar initialDate={initDate} markedDates={marked} onDayPress={(day) => { setSelected(day.dateString); props.onDaySelect && props.onDaySelect(day); }} {...props} /> ); } function App() { return ( <SafeAreaView style={styles.container}> <CustomCalendar onDaySelect={(day) => console.log(`Date selected: ${day.dateString}`)}/> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, }); export default App;
Here, we used the useMemo
Hook to memoize the marked
object and recompute it only if selected
is changed (for performance optimization). See how the above code implements selectable day elements:

The marked
boolean element renders a circle shape with several pre-included styles, but this library is flexible enough to offer the customStyles
prop for building a developer-defined shape style. The following code snippet renders a green rectangle when you press a day element:
function CustomCalendar(props) { const initDate = '2022-12-01'; const [selected, setSelected] = useState(initDate); const marked = useMemo(() => ({ [selected]: { customStyles: { container: { backgroundColor: 'green', borderRadius: 0, }, text: { color: 'white', } } } }), [selected]); return ( <Calendar initialDate="2022-12-01" markingType="custom" markedDates={marked} onDayPress={(day) => { setSelected(day.dateString); props.onDaySelect && props.onDaySelect(day); }} {...props} /> ); }
Here, we used markingType="custom"
to turn on the custom markers feature. The multi-dot
marking type lets us add multiple dot indicators into day elements, as if to indicate events on a particular day, as shown in the following code:
import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, } from 'react-native'; import { Calendar } from 'react-native-calendars'; function App() { const running = {key: 'running', color: 'blue'}; const cycling = {key: 'cycling', color: 'green'}; const walking = {key: 'walking', color: 'orange'}; const marked = { '2022-12-01': { dots: [running, walking] }, '2022-12-02': { dots: [running, walking, cycling] } }; return ( <SafeAreaView style={styles.container}> <Calendar initialDate="2022-12-01" markingType="multi-dot" markedDates={marked} /> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, }); export default App;
The above code generates a calendar component with multiple dot indicators in day elements:

Marking date ranges
We can write some code and implement a date-range marking style ourselves with customStyles
, but this library boosts developers’ productivity by offering an inbuilt date-range marking feature.
For example, you can mark the first ten days of December 2022 with the inbuilt range-marking feature as follows:
function App() { const getMarked = () => { let marked = {}; for(let i = 1; i <= 10; i++) { let day = i.toString().padStart(2, '0'); marked[`2022-12-${day}`] = { startingDay: i == 1, endingDay: i == 10, color: 'yellow', textColor: '#aaa', disabled: true, }; } return marked; }; return ( <SafeAreaView style={styles.container}> <Calendar initialDate="2022-12-01" markingType="period" markedDates={getMarked()} /> </SafeAreaView> ); };
Here, we use the getMarked
function to generate a ten-day-long period. The period start/end edge styling will change according to the startingDay
and endingDay
booleans. Once you run the above code snippet, you should see the following result:

It’s possible to build a date range selector component with this period marking feature. You can see a sample implementation from my GitHub repository.
This library offers an inbuilt multi-period-marking feature, too. Look at the following code:
function App() { const getMarked = () => { let marked = {}; for(let i = 1; i <= 10; i++) { let day = i.toString().padStart(2, '0'); let periods = [ { startingDay: i == 1, endingDay: i == 10, color: 'teal', }, (i >= 2 && i <= 6) && { startingDay: i == 2, endingDay: i == 6, color: 'orange', } ]; marked[`2022-12-${day}`] = { periods }; } return marked; }; return ( <SafeAreaView style={styles.container}> <Calendar initialDate="2022-12-01" markingType="multi-period" markedDates={getMarked()} /> </SafeAreaView> ); };
The above App
component implementation renders two date period lines between the 1st and the 10th of December 2022:

Want to display a quick summary of a few bookings in a calendar? Try the multi-period
marking type.
Customizing the calendar theme
Now, we already know how to do basic UI customizations; we changed the first weekday, disabled/hid the month navigation arrows, changed the month format, etc. What if we need to change the day element, header, weekday name colors, and fonts?
As mentioned in the highlighted features section, this library lets you change the look and feel by passing a custom theme object. If you feel that using a custom theme object is limiting, you can directly override stylesheet definitions of the calendar component. Moreover, you can customize the calendar component’s container styles.
First, look at the following example code and learn how to customize the calendar’s look and feel via the theme
prop, and the calendar container’s styles with the style
prop:
<Calendar initialDate="2022-12-01" style={{ borderRadius: 5, margin: 12, elevation: 5, borderWidth: 4, borderColor: 'rgba(100, 100, 100, 0.2)' }} theme={{ calendarBackground: '#222', dayTextColor: '#fff', textDisabledColor: '#444', monthTextColor: '#888' }} />
The above code snippet applies a dark color scheme to the calendar via the theme
prop and some styling enhancements for the calendar container via the style
prop. Look at the following preview:

The theme
prop offers a way to customize text styles and colors. But, we sometimes need to do advanced customizations using more styling definitions. For such scenarios, it’s possible to override stylesheet definitions. For example, you can override the calendar header style as follows:
theme={{ 'stylesheet.calendar.header': { headerContainer: { flexDirection: 'row', backgroundColor: '#eee', borderRadius: 12 }, } }}
Look at your style.ts
files by browsing the source and identify all style definitions that you can override via theme
. Check the end of a particular style.ts
file to find the stylesheet identifier (i.e., style.calendar.header
).
Styling weekend day headers
We can use stylesheet-overriding in the theme
prop to apply different styles for weekend day headers. For example, we can use green for Saturday headers and red for Sunday headers with the following theme object:
theme={{ 'stylesheet.calendar.header': { dayTextAtIndex0: { color: 'red' }, dayTextAtIndex6: { color: 'green' } } }}
Here is the preview for the above setup:

Using two different colors for weekend day numbers is also a good UI/UX improvement. But, the library doesn’t support customizing indexed day element styling as we used for customizing day headers via the theme
prop. So, we have to style weekend day numbers with markedDates
until the maintainers and contributors work on this pull request’s idea.
Creating scrollable calendar lists
Modern mobile apps often use more swipe events than traditional taps. For example, every popular social media app typically loads more posts when the user swipes up  —  not when the user taps a load-more-posts button. The Calendar
component is designed to navigate with arrows and see one month at a time, but you can use the CalendarList
component to create a modern infinite scroller-like calendar component.
Run the following code:
import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, } from 'react-native'; import { CalendarList } from 'react-native-calendars'; function App() { return ( <SafeAreaView style={styles.container}> <CalendarList/> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, }); export default App;
Now, you can see a scrollable calendar:

CalendarList
to create a scrollable calendarHowever, the Calendar
component is minimal, traditional, and generic, so consider selecting CalendarList
only if the screen is calendar-oriented (i.e., displaying within a Modal
) and users need to see multiple months at a time. The CalendarList
component accepts all Calendar
props and some additional props.
Using the Agenda
component for advanced use cases
In some scenarios, we need to implement agenda views in our React Native apps. The Calendar
and CalendarList
components support adding multi-period markers via the markedDates
prop, but the calendar component doesn’t have enough space to add a title and description for each marker line. So, implementing an agenda view with Calendar
or CalendarList
component is not a good decision.
The Agenda
component lets you create agenda views by displaying records for each day in a second view that gets opened after tapping a day element.
Run the following code to display a sample agenda view:
import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, } from 'react-native'; import { Agenda } from 'react-native-calendars'; function App() { return ( <SafeAreaView style={styles.container}> <Agenda selected="2022-12-01" items={{ '2022-12-01': [{name: 'Cycling'}, {name: 'Walking'}, {name: 'Running'}], '2022-12-02': [{name: 'Writing'}] }} renderItem={(item, isFirst) => ( <TouchableOpacity style={styles.item}> <Text style={styles.itemText}>{item.name}</Text> </TouchableOpacity> )} /> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' }, item: { backgroundColor: 'white', flex: 1, borderRadius: 5, padding: 10, marginRight: 10, marginTop: 17, }, itemText: { color: '#888', fontSize: 16, } }); export default App;
Here, we used the Agenda
component by providing day items via the items
prop. You can use the renderItem
callback to design a GUI for each day item. Check other callbacks and supported props from the official documentation on this GitHub repository.
Once you run the above code, you will see a minimal agenda view as follows:

Agenda
component preview in AndroidWe hardcoded several day items for demonstration purposes, but you can also use a remote web server to fetch data for your agenda view in production apps.
How to place calendar components
There are two key ways to render any GUI element in mobile apps: rendering on an app screen surface or rendering in a popup. I demonstrated all the above calendar component customizations directly on an app screen. If you use a calendar component as a user input element, showing it in a popup saves the current app screen’s space and improves overall usability.
Look at the following code:
import React, { useState } from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View, Modal, Button, } from 'react-native'; import { Calendar } from 'react-native-calendars'; function DatePicker({visible, onDateSelected}) { return ( <Modal visible={visible} transparent={true} animationType="fade"> <View style={styles.overlay}> <Calendar onDayPress={onDateSelected}/> </View> </Modal> ); } function App() { const [modalVisible, setModalVisible] = useState(false); return ( <SafeAreaView style={styles.container}> <Button title="Show Modal" onPress={() => setModalVisible(true)}/> <DatePicker visible={modalVisible} onDateSelected={() => setModalVisible(false)}/> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' }, overlay: { flex: 1, justifyContent: 'center', padding: 40, backgroundColor: 'rgba(100, 100, 100, 0.6)', }, }); export default App;
Here, we created the reusable DatePicker
component and showed a calendar component within a Modal
. Once you tap the button, the modal will appear with an overlay and a calendar component, as shown in the following preview:

react-native-calendars
components
In this tutorial, we discussed three popular components that react-native-calendars
offers:
Calendar
CalendarList
Agenda
We mainly focused on the Calendar
component because it lets you create customizable and shareable calendar components in your React Native apps, but the library offers a week calendar via WeekCalendar
, a timeline implementation via Timeline
, etc.
Check out all officially supported components from the official documentation. There are some undocumented components, but you can check them from the source.
react-native-calendars
alternatives
Like any other popular React Native package, react-native-calendars
also has alternative packages, but these alternatives are not so competitive with the react-native-calendars
package.
The reasons for this include:
- Most alternative packages focus on creating date pickers — not calendar views
- Some packages are not actively maintained and are deprecated (i.e.,
react-native-calendar
) - Some packages are new and are still becoming popular within the React Native community
However, it’s worth knowing about alternatives because they may become popular in the future and may offer unique features for your requirements. So, check out the following alternative libraries:
- react-native-calendario: A minimal, modern, scrollable calendar component that supports inbuilt range selection, date marking, and extensive style customization
- react-native-calendar-strip: A modern and customizable calendar component that displays days in one row
- react-native-calendar-picker: A date picker component that supports extensive style customization
- react-native-date-picker: A library that offers time, date, date-time picker components implemented in Java and Objective-C for better performance
Conclusion
We studied how to create shareable, customized calendars with the react-native-calendars
library. Code reusability boosts everyone’s productivity and improves software quality, so always strive to define a shareable calendar component if you repeat the same calendar props with the same values in multiple places.
Also, always care about your apps’ UI/UX factors by using a matching color theme for the calendar component and other UI elements. This library offers the Calendar
component as the main component, but check CalendarList
, Agenda
, and others, before selecting one for your requirement.
LogRocket: Instantly recreate issues in your React Native apps.

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.