Skip to main content
The Agenda component combines a calendar with a scrollable event list, perfect for displaying scheduled items and appointments. It features a collapsible calendar and efficient data loading.

Basic agenda setup

Create a simple agenda with dynamic item loading:
import React, {Component} from 'react';
import {Alert, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {Agenda} from 'react-native-calendars';

export default class AgendaScreen extends Component {
  state = {
    items: undefined
  };

  render() {
    return (
      <Agenda
        items={this.state.items}
        loadItemsForMonth={this.loadItems}
        selected={'2024-11-06'}
        renderItem={this.renderItem}
        renderEmptyDate={this.renderEmptyDate}
        rowHasChanged={this.rowHasChanged}
        showClosingKnob={true}
      />
    );
  }

  loadItems = (day) => {
    const items = this.state.items || {};

    setTimeout(() => {
      for (let i = -15; i < 85; i++) {
        const time = day.timestamp + i * 24 * 60 * 60 * 1000;
        const strTime = this.timeToString(time);

        if (!items[strTime]) {
          items[strTime] = [];
          
          const numItems = Math.floor(Math.random() * 3 + 1);
          for (let j = 0; j < numItems; j++) {
            items[strTime].push({
              name: 'Item for ' + strTime + ' #' + j,
              height: Math.max(50, Math.floor(Math.random() * 150)),
              day: strTime
            });
          }
        }
      }
      
      const newItems = {};
      Object.keys(items).forEach(key => {
        newItems[key] = items[key];
      });
      this.setState({
        items: newItems
      });
    }, 1000);
  };

  renderItem = (reservation, isFirst) => {
    const fontSize = isFirst ? 16 : 14;
    const color = isFirst ? 'black' : '#43515c';

    return (
      <TouchableOpacity
        style={[styles.item, {height: reservation.height}]}
        onPress={() => Alert.alert(reservation.name)}
      >
        <Text style={{fontSize, color}}>{reservation.name}</Text>
      </TouchableOpacity>
    );
  };

  renderEmptyDate = () => {
    return (
      <View style={styles.emptyDate}>
        <Text>This is empty date!</Text>
      </View>
    );
  };

  rowHasChanged = (r1, r2) => {
    return r1.name !== r2.name;
  };

  timeToString(time) {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
  }
}

const styles = StyleSheet.create({
  item: {
    backgroundColor: 'white',
    flex: 1,
    borderRadius: 5,
    padding: 10,
    marginRight: 10,
    marginTop: 17
  },
  emptyDate: {
    height: 15,
    flex: 1,
    paddingTop: 30
  }
});
The loadItemsForMonth callback is triggered when a new month becomes visible, allowing you to load items on-demand.

Agenda with marked dates

Combine agenda items with date marking:
import React, {Component} from 'react';
import {Agenda} from 'react-native-calendars';

export default class AgendaScreen extends Component {
  render() {
    return (
      <Agenda
        items={this.state.items}
        loadItemsForMonth={this.loadItems}
        selected={'2017-05-16'}
        renderItem={this.renderItem}
        renderEmptyDate={this.renderEmptyDate}
        rowHasChanged={this.rowHasChanged}
        showClosingKnob={true}
        markingType={'period'}
        markedDates={{
          '2017-05-08': {textColor: '#43515c'},
          '2017-05-09': {textColor: '#43515c'},
          '2017-05-14': {startingDay: true, endingDay: true, color: 'blue'},
          '2017-05-21': {startingDay: true, color: 'blue'},
          '2017-05-22': {endingDay: true, color: 'gray'},
          '2017-05-24': {startingDay: true, color: 'gray'},
          '2017-05-25': {color: 'gray'},
          '2017-05-26': {endingDay: true, color: 'gray'}
        }}
      />
    );
  }
}
You can use any marking type (simple, multi-dot, period, multi-period, custom) with the Agenda component.

Custom theme for agenda

Style your agenda with custom colors:
import React from 'react';
import {Agenda} from 'react-native-calendars';

const App = () => {
  return (
    <Agenda
      items={items}
      loadItemsForMonth={loadItems}
      selected={'2024-11-06'}
      renderItem={renderItem}
      renderEmptyDate={renderEmptyDate}
      theme={{
        calendarBackground: '#ffffff',
        agendaKnobColor: '#0066cc',
        selectedDayBackgroundColor: '#0066cc',
        selectedDayTextColor: '#ffffff',
        todayTextColor: '#0066cc',
        dayTextColor: '#2d4150',
        textDisabledColor: '#d9e1e8',
        dotColor: '#0066cc',
        agendaDayTextColor: '#0066cc',
        agendaDayNumColor: '#0066cc',
        agendaTodayColor: '#ff0000'
      }}
    />
  );
};

export default App;

Data structure

The Agenda component expects items in this format:
const items = {
  '2024-11-06': [
    {
      name: 'Meeting with team',
      height: 80,
      day: '2024-11-06'
    },
    {
      name: 'Lunch appointment',
      height: 60,
      day: '2024-11-06'
    }
  ],
  '2024-11-07': [
    {
      name: 'Conference call',
      height: 100,
      day: '2024-11-07'
    }
  ],
  '2024-11-08': [], // Empty day
  // Date not included means not loaded yet
};
Dates with an empty array [] are rendered as empty dates. Dates not included in the object are considered not yet loaded.

Custom day rendering

Customize how days are rendered in the calendar:
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {Agenda} from 'react-native-calendars';

const App = () => {
  const renderDay = (day) => {
    if (day) {
      return <Text style={styles.customDay}>{day.getDay()}</Text>;
    }
    return <View style={styles.dayItem}/>;
  };

  return (
    <Agenda
      items={items}
      loadItemsForMonth={loadItems}
      renderItem={renderItem}
      renderDay={renderDay}
    />
  );
};

const styles = StyleSheet.create({
  customDay: {
    margin: 10,
    fontSize: 24,
    color: 'green'
  },
  dayItem: {
    marginLeft: 34
  }
});

export default App;

Agenda key props

<Agenda
  // Items to display {[date]: [items]}
  items={items}
  
  // Callback when month becomes visible
  loadItemsForMonth={(day) => {}}
  
  // Initially selected day
  selected={'2024-11-06'}
  
  // Render function for agenda items
  renderItem={(item, isFirst) => <View />}
  
  // Render function for empty dates
  renderEmptyDate={() => <View />}
  
  // Callback to determine if row changed
  rowHasChanged={(r1, r2) => r1 !== r2}
/>

Callbacks

The Agenda component provides several useful callbacks:
<Agenda
  // Called when calendar is opened/closed
  onCalendarToggled={(enabled) => {
    console.log('Calendar is', enabled ? 'open' : 'closed');
  }}
  
  // Called when day changes while scrolling
  onDayChange={(day) => {
    console.log('Day changed to:', day.dateString);
  }}
  
  // Called when day is pressed
  onDayPress={(day) => {
    console.log('Day pressed:', day.dateString);
  }}
/>

Custom item rendering

Create rich, interactive agenda items:
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';

const renderItem = (item, isFirst) => {
  return (
    <TouchableOpacity style={styles.item}>
      <View style={styles.itemContent}>
        <Text style={styles.itemTitle}>{item.name}</Text>
        <Text style={styles.itemTime}>{item.time}</Text>
        <Text style={styles.itemDescription}>{item.description}</Text>
      </View>
      {item.attendees && (
        <View style={styles.attendees}>
          {item.attendees.map((attendee, index) => (
            <Text key={index} style={styles.attendee}>{attendee}</Text>
          ))}
        </View>
      )}
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  item: {
    backgroundColor: 'white',
    borderRadius: 8,
    padding: 16,
    marginRight: 10,
    marginTop: 17,
    shadowColor: '#000',
    shadowOffset: {width: 0, height: 2},
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3
  },
  itemContent: {
    marginBottom: 8
  },
  itemTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#212529',
    marginBottom: 4
  },
  itemTime: {
    fontSize: 14,
    color: '#6c757d',
    marginBottom: 4
  },
  itemDescription: {
    fontSize: 14,
    color: '#495057'
  },
  attendees: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    marginTop: 8
  },
  attendee: {
    fontSize: 12,
    color: '#0066cc',
    marginRight: 8,
    padding: 4,
    backgroundColor: '#e7f3ff',
    borderRadius: 4
  }
});
The isFirst parameter in renderItem indicates if this is the first item of the day, useful for different styling.

Build docs developers (and LLMs) love