Load Public Google Calendar Events
Usage
theme="ios" You can turn auto theming on and let it decide based on the platform.
Usage
themeVariant="light" You can turn auto dark mode on based on system settings.
Usage
locale={localeEn} Selecting the locale loads the localized settings and the translated UI text.
Load Public Google Calendar Events
Event data can be loaded from remote sources, like public google calendars. Through the integration plugin you can easily show events that are available in a public calendar. The integration plugin needs to be added to the download package or installed separately from a dedicated NPM package.
You will just need the CALENDAR_ID and an apiKey from google and you should be ready to roll.
Public calendars are read-only. If you are interested in syncing private google calendars with read/write/delete access, check out this example.
Demo

Code
View code on GitHub
import { googleCalendarSync } from '@mobiscroll/calendar-integration';
import {
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Eventcalendar,
Segmented,
SegmentedGroup,
setOptions,
Toast ,
} from '@mobiscroll/react';
import { useCallback, useEffect, useRef, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const CALENDAR_ID = 'theacidmedia.net_8l6v679q5j2f7q8lpmcjr4mm3k@group.calendar.google.com';
function App() {
const [currentView, setCurrentView] = useState('agenda');
const [isLoading, setLoading] = useState(false);
const [isToastOpen, setToastOpen] = useState(false);
const [myEvents, setEvents] = useState([]);
const [myView, setView] = useState({
calendar: { type: 'week' },
agenda: { type: 'week' },
});
const [toastMessage, setToastMessage] = useState('');
const firstDay = useRef();
const lastDay = useRef();
const handleError = useCallback((resp) => {
setToastMessage(resp.error ? resp.error : resp.result.error.message);
setToastOpen(true);
}, []);
const loadEvents = useCallback(() => {
setTimeout(() => {
setLoading(true);
});
googleCalendarSync
.getEvents(CALENDAR_ID, firstDay.current, lastDay.current)
.then((resp) => {
setEvents(resp);
setLoading(false);
})
.catch(handleError);
}, [handleError]);
const changeView = useCallback((event) => {
let view;
switch (event.target.value) {
case 'month':
view = {
calendar: { type: 'month' },
};
break;
case 'week':
view = {
scheduler: { type: 'week' },
};
break;
case 'day':
view = {
scheduler: { type: 'day' },
};
break;
case 'agenda':
default:
view = {
calendar: { type: 'week' },
agenda: { type: 'week' },
};
break;
}
setCurrentView(event.target.value);
setView(view);
}, []);
const handlePageLoading = useCallback(
(event) => {
const start = event.viewStart;
const end = event.viewEnd;
// Calculate dates
// (pre-load events for previous and next pages as well)
if (currentView === 'month') {
firstDay.current = start;
lastDay.current = end;
} else {
firstDay.current = new Date(start.getFullYear(), start.getMonth(), start.getDate() - 7);
lastDay.current = new Date(end.getFullYear(), end.getMonth(), end.getDate() + 7);
}
loadEvents();
},
[loadEvents, currentView],
);
const handleCloseToast = useCallback(() => {
setToastOpen(false);
}, []);
const customHeader = useCallback(
() => (
<>
<CalendarNav className="mds-google-cal-nav" />
<div className={'mds-loader' + (isLoading ? ' mds-loader-visible' : '')}></div>
<div className="mds-google-cal-switch mbsc-flex-1-0">
<SegmentedGroup value={currentView} onChange={changeView}>
<Segmented value="month">Month</Segmented>
<Segmented value="week">Week</Segmented>
<Segmented value="day">Day</Segmented>
<Segmented value="agenda">Agenda</Segmented>
</SegmentedGroup>
</div>
<CalendarPrev className="mds-google-cal-prev" />
<CalendarToday className="mds-google-cal-today" />
<CalendarNext className="mds-google-cal-next" />
</>
),
[changeView, currentView, isLoading],
);
useEffect(() => {
googleCalendarSync.init({
apiKey: '<YOUR_GOOGLE_API_KEY>',
onInit: loadEvents,
});
}, [loadEvents]);
return (
<>
<Eventcalendar data={myEvents} exclusiveEndDates={true} renderHeader={customHeader} view={myView} onPageLoading={handlePageLoading} />
<Toast isOpen={isToastOpen} message={toastMessage} onClose={handleCloseToast} />
</>
);
}
export default App;
import { googleCalendarSync } from '@mobiscroll/calendar-integration';
import {
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Eventcalendar,
MbscCalendarEvent,
MbscEventcalendarView,
MbscPageLoadingEvent,
Segmented,
SegmentedGroup,
setOptions,
Toast ,
} from '@mobiscroll/react';
import { ChangeEvent, FC, useCallback, useEffect, useRef, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const CALENDAR_ID = 'theacidmedia.net_8l6v679q5j2f7q8lpmcjr4mm3k@group.calendar.google.com';
const App: FC = () => {
const [currentView, setCurrentView] = useState<string>('agenda');
const [isLoading, setLoading] = useState<boolean>(false);
const [isToastOpen, setToastOpen] = useState<boolean>(false);
const [myEvents, setEvents] = useState<MbscCalendarEvent[]>([]);
const [myView, setMyView] = useState<MbscEventcalendarView>({
calendar: { type: 'week' },
agenda: { type: 'week' },
});
const [toastMessage, setToastMessage] = useState<string>('');
const firstDay = useRef<Date>(null);
const lastDay = useRef<Date>(null);
const handleError = useCallback((resp: { error: string; result: { error: { message: string } } }) => {
setToastMessage(resp.error ? resp.error : resp.result.error.message);
setToastOpen(true);
}, []);
const loadEvents = useCallback(() => {
setTimeout(() => {
setLoading(true);
});
googleCalendarSync
.getEvents(CALENDAR_ID, firstDay.current!, lastDay.current!)
.then((resp: MbscCalendarEvent[]) => {
setLoading(false);
setEvents(resp);
})
.catch(handleError);
}, [firstDay, lastDay, handleError]);
const changeView = (event: ChangeEvent<HTMLInputElement>) => {
let view: MbscEventcalendarView;
switch (event.target.value) {
case 'month':
view = {
calendar: { type: 'month' },
};
break;
case 'week':
view = {
scheduler: { type: 'week' },
};
break;
case 'day':
view = {
scheduler: { type: 'day' },
};
break;
case 'agenda':
default:
view = {
calendar: { type: 'week' },
agenda: { type: 'week' },
};
break;
}
setCurrentView(event.target.value);
setMyView(view);
};
const handlePageLoading = useCallback(
(event: MbscPageLoadingEvent) => {
const start = event.viewStart;
const end = event.viewEnd;
// Calculate dates
// (pre-load events for previous and next pages as well)
if (currentView === 'month') {
firstDay.current = start;
lastDay.current = end;
} else {
firstDay.current = new Date(start!.getFullYear(), start!.getMonth(), start!.getDate() - 7);
lastDay.current = new Date(end!.getFullYear(), end!.getMonth(), end!.getDate() + 7);
}
loadEvents();
},
[loadEvents, currentView],
);
const handleCloseToast = useCallback(() => {
setToastOpen(false);
}, []);
const customHeader = () => (
<>
<CalendarNav className="mds-google-cal-nav" />
<div className={'mds-loader' + (isLoading ? ' mds-loader-visible' : '')}></div>
<div className="mds-google-cal-switch mbsc-flex-1-0">
<SegmentedGroup value={currentView} onChange={changeView}>
<Segmented value="month">Month</Segmented>
<Segmented value="week">Week</Segmented>
<Segmented value="day">Day</Segmented>
<Segmented value="agenda">Agenda</Segmented>
</SegmentedGroup>
</div>
<CalendarPrev className="mds-google-cal-prev" />
<CalendarToday className="mds-google-cal-today" />
<CalendarNext className="mds-google-cal-next" />
</>
);
useEffect(() => {
googleCalendarSync.init({
apiKey: '<YOUR_GOOGLE_API_KEY>',
onInit: loadEvents,
});
}, [loadEvents]);
return (
<>
<Eventcalendar data={myEvents} exclusiveEndDates={true} renderHeader={customHeader} view={myView} onPageLoading={handlePageLoading} />
<Toast isOpen={isToastOpen} message={toastMessage} onClose={handleCloseToast} />
</>
);
};
export default App;
.mds-google-cal-switch .mbsc-segmented {
max-width: 300px;
margin: 0 auto;
}
.mds-google-cal-nav {
width: 200px;
}
.mds-loader {
width: 32px;
height: 32px;
border: 4px solid #8c8c8c;
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: mds-loader-rotation 1s linear infinite;
visibility: hidden;
}
.mds-loader-visible {
visibility: visible;
}
@keyframes mds-loader-rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Material header order */
.mbsc-material.mds-google-cal-prev {
order: 1;
}
.mbsc-material.mds-google-cal-next {
order: 2;
}
.mbsc-material.mds-google-cal-nav {
order: 3;
}
.mbsc-material .mds-google-cal-switch {
order: 4;
}
.mbsc-material .mds-google-cal-today {
order: 5;
}
/* Windows header order */
.mbsc-windows.mds-google-cal-nav {
order: 1;
}
.mbsc-windows.mds-google-cal-prev {
order: 2;
}
.mbsc-windows.mds-google-cal-next {
order: 3;
}
.mbsc-windows .mds-google-cal-switch {
order: 4;
}
.mbsc-windows .mds-google-cal-today {
order: 5;
}