How I built horizontal as well as grid calendar in react-native using react-native-calendars

Varun Kumar
The Startup
Published in
4 min readFeb 24, 2019

--

Recently at my current company, I got a project where I had to make a calendar UI in react-native. Calendar needed to support both — horizontal as well as grid view. Mocks provided was something like this-

calendar in grid and list format

I searched online and found react-native-calendars library https://github.com/wix/react-native-calendars which was matching my requirement up to 80%. It has following Calendar component-

react-native-calendars Calendar component

There were few issues-

  1. I needed a custom calendar header which react-native-calendars has no support (as of now)
  2. Calendar had to support horizontal strip view as well
  3. I needed custom day component to suit my project need

Third issue was solved as react-native-calendars has support for custom day component, so all I had to was write my own Day Component and pass it as prop dayComponent={CalendarDayComponent}.

To solve the first issue, I deep dived into source code and added support for two more props- calendarHeaderComponent and headerData. Basically I am checking if user is providing his own header component, if yes then use it and pass headerData as an additional props to it, if not then fallback to existing header component. headerData is an object which can contain information such as selected date to show in calendar header.

I created this Pull Request with above changes (not merged as of now)- https://github.com/wix/react-native-calendars/pull/747

The main issue to solve was providing support for horizontal calendar. I used ScrollView with horizontal property to show a horizontal calendar. I added a new props horizontal to distinguish between horizontal/grid calendar view.

  {
this.props.horizontal ?
<ScrollView
style={[this.style.monthView, {flex: 1}]}
horizontal
ref={this.horizontalScrollViewRef}
>
{weeks}
</ScrollView>
: <View style={this.style.monthView}>{weeks}</View>
}

So the problem solved? Yes but there was one more issue- above code was showing weeks of selected month in horizontal scrollbar, and at a time only ~8 days were visible (unlike grid view where all days of month were visible). So if selected day was mid/last part of month, it was not visible and user had to scroll to show it. This might create confusion to user so I had to find a way to auto scroll the calendar to make selected day visible. To solve this, I programmatically scrolled calendar to required offset after render was celled.

  // scroll the horizontal calendar to make selected date visible
componentDidUpdate() {
const horizontalScrollView =
this.horizontalScrollViewRef.current;
if (horizontalScrollView) {
const windowWidth = Dimensions.get('window').width;
horizontalScrollView.scrollTo({
x: horizontalScrollViewOffset * windowWidth,
animated: true
});
}
}

To give final touch to library, I added two new props onPressListView and onPressGridView to toggle calendar view.

How to use this customized calendar in your project?

I forked react-native-calendars repo and made all changes in branch horizontal_calendar. To use modified library in your project, add package using github url in your package.json-

"react-native-calendars": "git://git@github.com/varunon9/react-native-toggle-calendar.git#horizontal_calendar"

Then you can use it like below-

<Calendar
current=
{this.state.calendarDate}
dayComponent={CalendarDayComponent}
calendarHeaderComponent={CalendarHeaderComponent}
headerData={{
calendarDate: calendarDate.format('DD MMM, YYYY')
}}
style={{
paddingLeft: 0, paddingRight: 0
}}
onPressArrowLeft={this.onPressArrowLeft}
onPressArrowRight={this.onPressArrowRight}
onPressListView={this.onPressListView}
onPressGridView={this.onPressGridView}
markedDates={{
'2019-02-23': {soldOut: false, blocked: false, inventory: 2},
'2019-02-24': {soldOut: false, blocked: false, inventory: 2},
'2019-02-25': {soldOut: false, blocked: true, inventory: 0},
'2019-02-26': {soldOut: true, blocked: true, inventory: 2}
}}
horizontal={this.state.horizontal}
onDayPress={this.onDayPress}
/>

Final Result-

react-native-toggle-calendar

Full code -

End Note

I am new to react-native and I really enjoyed this customization. I am waiting for my PR to be merged to official react-native-calendars repository, till then I am using github repository as dependency package. As a bonus, this library is compatible with react-native-web :D

Url: https://github.com/varunon9/react-native-toggle-calendar/tree/horizontal_calendar
Example: https://github.com/varunon9/react-native-toggle-calendar/tree/master/ToggleCalendar

This story is published in The Startup, Medium’s largest entrepreneurship publication followed by +428,678 people.

Subscribe to receive our top stories here.

--

--

Varun Kumar
The Startup

Full Stack Developer | I turn ideas into Products