React Native Calendars
react-native-calendars is a comprehensive and highly customizable set of calendar components designed for React Native applications. It provides a variety of views including a standard month calendar, a scrollable list of calendars (CalendarList), an agenda view combining a calendar with an event list, and expandable week views. The library is actively maintained with frequent releases, often multiple times a week or month, indicating rapid development and responsiveness to bug fixes and feature requests. The current stable version is 1.1314.0. Key differentiators include extensive styling options, support for marking specific dates with various styles (dots, periods, custom backgrounds), and accessibility features. It aims to offer a robust solution for displaying and interacting with date information in mobile applications without requiring complex native module linking beyond standard React Native setup.
Common errors
-
Warning: Each child in a list should have a unique "key" prop.
cause This warning typically occurs when rendering iterated components within `CalendarList`, `AgendaList`, or `WeekCalendar` without providing a stable, unique `key` prop for each item. The changelog for 1.1313.0 specifically mentions a fix for `WeekCalendar` related to this.fixEnsure that any data you iterate over to render components (e.g., event items in `Agenda`, custom day components) has a unique identifier, and assign it to the `key` prop: `<MyComponent key={item.id} />` or use `keyExtractor` for `FlatList` based components to provide unique keys for each rendered item. -
TypeError: Cannot read property 'map' of undefined (or similar errors related to `markedDates` or `items` prop)
cause This usually indicates that the `markedDates` prop for `Calendar` / `CalendarList` or the `items` prop for `Agenda` is not in the expected data structure (e.g., `markedDates` is not an object, or `items` is `null`/`undefined` when the component expects an object with date string keys).fixVerify the structure of your `markedDates` object (it should be `{ 'YYYY-MM-DD': { /* marking data */ } }` ) and `items` object (it should be `{ 'YYYY-MM-DD': [ /* event objects */ ] }` ) against the library's documentation. Ensure these props are always initialized to an empty object `{}` rather than `null` or `undefined` if no data is available. -
Calendar/Agenda view does not update visually after changing date data (e.g., `markedDates`, `items`) in state.
cause React performs shallow comparisons on props. If you mutate an existing object (e.g., `markedDates`) directly rather than creating a new object with the updated data, React won't detect the change and won't trigger a re-render of the component.fixAlways create a *new* object for props like `markedDates` and `items` when their content changes. For example, use spread syntax (`{ ...oldMarkedDates, [newDate]: newMarking }`) or `Object.assign` to ensure React detects a prop change and triggers a re-render. Similarly, for arrays, use `.map()`, `.filter()`, or spread syntax (`[...oldArray, newItem]`) instead of `.push()` or direct modification.
Warnings
- gotcha The library undergoes very frequent updates, often multiple times a week. While this indicates active development, it means developers should frequently review changelogs and consider precise dependency pinning to avoid unexpected behavior changes or regressions in minor versions.
- gotcha Managing complex `markedDates` objects, especially with many dates or dynamic custom styling functions, can lead to performance degradation, particularly on lower-end devices or with very large date ranges. Incorrectly formatted `markedDates` can also cause render errors.
- breaking Version 1.1314.0 removed `react-native-safe-area-context` as an unused dependency. While this is a cleanup, if your project implicitly relied on this library being present in `node_modules` through `react-native-calendars`, you might encounter runtime issues if `react-native-safe-area-context` is not explicitly installed and linked in your project.
- gotcha Customizing the appearance of calendar components can sometimes be challenging due to the nested structure of React Native components and potential style conflicts. Achieving pixel-perfect designs often requires deep inspection of the component hierarchy or careful use of provided `theme` and `style` props.
- gotcha Ensuring full accessibility across all custom calendar implementations (e.g., custom headers, day renderings) requires careful attention to `accessibilityLabel`, `accessible`, and `role` props, which can be easily overlooked, leading to poor user experience for assistive technology users.
Install
-
npm install react-native-calendars -
yarn add react-native-calendars -
pnpm add react-native-calendars
Imports
- Calendar
const Calendar = require('react-native-calendars')import { Calendar } from 'react-native-calendars' - CalendarList
import CalendarList from 'react-native-calendars'
import { CalendarList } from 'react-native-calendars' - Agenda
import { agenda } from 'react-native-calendars'import { Agenda } from 'react-native-calendars' - LocaleConfig
import { LocaleConfig } from 'react-native-calendars'
Quickstart
import React, { useState, useCallback } from 'react';
import { SafeAreaView, StyleSheet, Text, View } from 'react-native';
import { Calendar, LocaleConfig } from 'react-native-calendars';
// Configure localization (optional)
LocaleConfig.locales['en'] = {
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan.','Feb.','Mar.','Apr.','May.','Jun.','Jul.','Aug.','Sep.','Oct.','Nov.','Dec.'],
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
dayNamesShort: ['Sun.','Mon.','Tue.','Wed.','Thu.','Fri.','Sat.'],
today: 'Today'
};
LocaleConfig.defaultLocale = 'en';
const App = () => {
const [selected, setSelected] = useState('');
const onDayPress = useCallback((day) => {
setSelected(day.dateString);
}, []);
// Define marked dates for special styling
const markedDates = {
[selected]: {
selected: true,
disableTouchEvent: true,
selectedColor: 'orange',
selectedTextColor: 'white'
},
'2026-04-20': {dots: [{key: 'vacation', color: 'blue', selectedDotColor: 'blue'}]},
'2026-04-21': {marked: true, dotColor: 'red'},
'2026-04-22': {selected: true, marked: true, selectedColor: 'purple', customStyles: { text: { color: 'white' } }}
};
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>My Calendar App</Text>
<Calendar
onDayPress={onDayPress}
markedDates={markedDates}
enableSwipeMonths={true}
hideExtraDays={true}
showWeekNumbers={true}
firstDay={1} // Monday as first day of the week
style={styles.calendar}
theme={{
selectedDayBackgroundColor: '#00adf5',
todayTextColor: '#00adf5',
arrowColor: 'orange',
indicatorColor: 'orange',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '500',
backgroundColor: '#ffffff'
}}
/>
{selected && <Text style={styles.selectedDayText}>Selected day: {selected}</Text>}
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5fcff',
paddingTop: 50, // Ensure content is below status bar
},
title: {
fontSize: 24,
textAlign: 'center',
marginBottom: 20,
fontWeight: 'bold',
color: '#333',
},
calendar: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 10,
marginHorizontal: 15,
padding: 10,
elevation: 3, // Android shadow
shadowColor: '#000', // iOS shadow
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
selectedDayText: {
fontSize: 18,
textAlign: 'center',
marginTop: 30,
fontWeight: '600',
color: '#00adf5',
},
});
export default App;