Outlook Integration
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
clickToCreate={true}
// click to create is on dragToCreate={true}
// drag to create is on dragToMove={true}
// reordering is on dragToResize={true}
// resizing is on eventDelete={true}
// deleting is on Fine-tune drag & drop with these options, which are false by default.
Usage
locale={localeEn} Selecting the locale loads the localized settings and the translated UI text.
Outlook Integration
The event calendar comes with third party calendar integration support through the integration plugin. This needs to be added to the download package or installed separately from a dedicated NPM package.
It includes everything you need to authenticate your users, get their Outlook calendars and provides functions for CRUD operations. It takes care of loading the events and converts them to the required format so that they can be displayed on the Mobiscroll calendar separately or mixed with other calendars and events.
Customizing the interaction, event workflows, whether the events are read-only is up to you. In this live demo, newly created events will land in the primary calendar of the authenticated user.
Demo
The live demo didn't load.
Try it on demo.mobiscroll.comLog into your Outlook account to view and edit your Outlook Calendar events
Editing events sync back to your calendar when enabled. You'll be asked for confirmation on every action.

Code
View code on GitHub
import { outlookCalendarSync } from '@mobiscroll/calendar-integration';
import {
Button,
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Confirm,
Eventcalendar,
Page,
setOptions,
Switch,
Toast ,
} from '@mobiscroll/react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
function App() {
const [myEvents, setEvents] = useState([]);
const [myCalendars, setCalendars] = useState([]);
const [calendarIds, setCalendarIds] = useState([]);
const [calendarData, setCalendarData] = useState([]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [editable, setEditable] = useState(false);
const [isLoading, setLoading] = useState(false);
const [primaryCalendarId, setPrimaryCalendarId] = useState();
const [isToastOpen, setToastOpen] = useState(false);
const [toastMessage, setToastMessage] = useState('');
const [confirmEvent, setConfirmEvent] = useState();
const [confirmOldEvent, setConfirmOldEvent] = useState();
const [isUpdateConfirmOpen, setUpdateConfirmOpen] = useState(false);
const [isDeleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
const debounce = useRef();
const startDate = useRef();
const endDate = useRef();
const view = useMemo(() => ({ calendar: { labels: true } }), []);
const handleError = useCallback((resp) => {
setToastMessage(resp.message);
setToastOpen(true);
}, []);
const handleToastClose = useCallback(() => {
setToastOpen(false);
}, []);
const handlePageLoading = useCallback(
(args) => {
clearTimeout(debounce.current);
startDate.current = args.viewStart;
endDate.current = args.viewEnd;
debounce.current = setTimeout(() => {
if (outlookCalendarSync.isSignedIn()) {
setLoading(true);
outlookCalendarSync
.getEvents(calendarIds, startDate.current, endDate.current)
.then((events) => {
setLoading(false);
setEvents(events);
})
.catch(handleError);
}
}, 200);
},
[calendarIds, handleError],
);
const handleEventCreate = useCallback(
(args) => {
if (outlookCalendarSync.isSignedIn()) {
const event = args.event;
outlookCalendarSync
.addEvent(primaryCalendarId, event)
.then((newEvent) => {
newEvent.color = event.color;
setEvents((oldEvents) => [...oldEvents, newEvent]);
setToastMessage('Event created in "' + calendarData[primaryCalendarId].name + '" calendar');
setToastOpen(true);
})
.catch((error) => {
setEvents((oldEvents) => [...oldEvents]);
handleError(error);
});
}
},
[calendarData, handleError, primaryCalendarId],
);
const handleEventUpdate = useCallback((args) => {
if (outlookCalendarSync.isSignedIn()) {
setConfirmEvent(args.event);
setConfirmOldEvent(args.oldEvent);
setUpdateConfirmOpen(true);
}
}, []);
const handleEventDelete = useCallback((args) => {
if (outlookCalendarSync.isSignedIn()) {
setConfirmEvent(args.event);
setDeleteConfirmOpen(true);
}
return false;
}, []);
const extendDefaultEvent = useCallback(
() => ({
color: calendarData[primaryCalendarId].color,
}),
[calendarData, primaryCalendarId],
);
const signIn = useCallback(() => {
outlookCalendarSync.signIn().catch(handleError);
}, [handleError]);
const signOut = useCallback(() => {
outlookCalendarSync.signOut().catch(handleError);
}, [handleError]);
const toggleEditing = useCallback((ev) => {
setEditable(ev.target.checked);
}, []);
const toggleCalendar = useCallback(
(ev) => {
const checked = ev.target.checked;
const calendarId = ev.target.value;
const updatedCalendarData = { ...calendarData, [calendarId]: { ...calendarData[calendarId], checked } };
setCalendarData(updatedCalendarData);
if (checked) {
setLoading(true);
setCalendarIds((calIds) => [...calIds, calendarId]);
outlookCalendarSync
.getEvents([calendarId], startDate.current, endDate.current)
.then((events) => {
setLoading(false);
setEvents((oldEvents) => [...oldEvents, ...events]);
})
.catch(handleError);
} else {
setCalendarIds((calIds) => calIds.filter((item) => item !== calendarId));
setEvents((oldEvents) => oldEvents.filter((item) => item.outlookCalendarId !== calendarId));
}
},
[calendarData, handleError],
);
const renderMyHeader = useCallback(
() => (
<>
<CalendarNav />
<div className="md-spinner">
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
</div>
<div className="md-outlook-calendar-header">
<CalendarPrev />
<CalendarToday />
<CalendarNext />
</div>
</>
),
[],
);
const handleUpdateConfirmClose = useCallback(
(result) => {
if (result) {
const calendarId = confirmEvent.outlookCalendarId;
outlookCalendarSync
.updateEvent(calendarId, confirmEvent)
.then(() => {
setToastMessage('Event updated on "' + calendarData[calendarId].name + '" calendar');
setToastOpen(true);
})
.catch((error) => {
setEvents((oldEvents) => [...oldEvents.filter((item) => item.id !== confirmEvent.id), confirmOldEvent]);
handleError(error);
});
} else {
setEvents((oldEvents) => [...oldEvents.filter((item) => item.id !== confirmEvent.id), confirmOldEvent]);
}
setUpdateConfirmOpen(false);
},
[calendarData, confirmEvent, confirmOldEvent, handleError],
);
const handleDeleteConfirmClose = useCallback(
(result) => {
if (result) {
const calendarId = confirmEvent.outlookCalendarId;
outlookCalendarSync
.deleteEvent(calendarId, confirmEvent)
.then(() => {
setEvents((oldEvents) => oldEvents.filter((item) => item.id !== confirmEvent.id));
setToastMessage('Event deleted from "' + calendarData[calendarId].name + '" calendar');
setToastOpen(true);
})
.catch(handleError);
}
setDeleteConfirmOpen(false);
},
[calendarData, confirmEvent, handleError],
);
useEffect(() => {
const onSignedIn = () => {
setIsLoggedIn(true);
outlookCalendarSync
.getCalendars()
.then((calendars) => {
calendars.sort((c) => (c.isDefaultCalendar ? -1 : 1));
const calData = {};
const primaryCalId = calendars[0].id;
for (const c of calendars) {
calData[c.id] = { name: c.name, color: c.hexColor, checked: c.id === primaryCalId };
}
setCalendarIds([primaryCalId]);
setPrimaryCalendarId(primaryCalId);
setCalendarData(calData);
setCalendars(calendars);
setLoading(true);
return outlookCalendarSync.getEvents([primaryCalId], startDate.current, endDate.current);
})
.then((events) => {
setEvents(events);
setLoading(false);
})
.catch(handleError);
};
const onSignedOut = () => {
setIsLoggedIn(false);
setCalendars([]);
setCalendarIds([]);
setCalendarData({});
setEvents([]);
};
// Init outlook client
outlookCalendarSync.init({
clientId: '<YOUR_OUTLOOK_CLIENT_ID>',
redirectUri: '<YOUR_OUTLOOK_REDIRECT_URI>',
onSignedIn: onSignedIn,
onSignedOut: onSignedOut,
});
}, [handleError]);
return (
<Page className="md-sync-events-outlook-cont">
<div className="md-sync-events-outlook-menu">
{isLoggedIn ? (
<div>
<div className="mbsc-form-group-inset mbsc-align-center">
<p className="mbsc-italic mbsc-txt-muted">
Editing events sync back to your calendar when enabled. You'll be asked for confirmation on every action.
</p>
</div>
<div className="mbsc-form-group-inset">
<Switch label="Enable editing" checked={editable} onChange={toggleEditing} />
</div>
<div className="mbsc-form-group-inset md-sync-events-outlook-inset">
<div className="mbsc-form-group-title">My Calendars</div>
{myCalendars.map((cal) => (
<Switch label={cal.name} key={cal.id} value={cal.id} checked={calendarData[cal.id].checked} onChange={toggleCalendar} />
))}
</div>
<div className="mbsc-form-group-inset">
<Button className="md-sync-events-outlook-button mbsc-button-block" onClick={signOut}>
Log out of my account
</Button>
</div>
</div>
) : (
<div>
<div className="mbsc-form-group-inset mbsc-align-center">
<p className="mbsc-italic mbsc-txt-muted">Log into your Outlook account to view and edit your Outlook Calendar events</p>
<Button className="md-sync-events-outlook-button mbsc-button-block" onClick={signIn}>
Sync my outlook calendars
</Button>
</div>
</div>
)}
</div>
<div className={'md-sync-events-outlook-calendar ' + (isLoading ? 'md-loading-events' : '')}>
<div className="md-sync-events-overlay"></div>
<Eventcalendar
view={view}
data={myEvents}
exclusiveEndDates={true}
clickToCreate={editable}
dragToCreate={editable}
dragToMove={editable}
dragToResize={editable}
extendDefaultEvent={extendDefaultEvent}
renderHeader={renderMyHeader}
onPageLoading={handlePageLoading}
onEventCreate={handleEventCreate}
onEventUpdate={handleEventUpdate}
onEventDelete={handleEventDelete}
/>
</div>
<Toast isOpen={isToastOpen} message={toastMessage} onClose={handleToastClose} />
<Confirm
isOpen={isUpdateConfirmOpen}
title="Are you sure you want to update this event?"
message="This action will affect your Outlook Calendar event."
okText="Update"
onClose={handleUpdateConfirmClose}
/>
<Confirm
isOpen={isDeleteConfirmOpen}
title="Are you sure you want to delete this event?"
message="This action will remove the event from your Outlook Calendar as well."
okText="Delete"
onClose={handleDeleteConfirmClose}
/>
</Page>
);
}
export default App;
import { outlookCalendarSync } from '@mobiscroll/calendar-integration';
import {
Button,
CalendarNav,
CalendarNext,
CalendarPrev,
CalendarToday,
Confirm,
Eventcalendar,
MbscCalendarEvent,
MbscEventcalendarView,
MbscEventCreateEvent,
MbscEventDeleteEvent,
MbscEventUpdateEvent,
MbscPageLoadingEvent,
Page,
setOptions,
Switch,
Toast,
} from '@mobiscroll/react';
import { ChangeEvent, FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const App: FC = () => {
const [myEvents, setEvents] = useState<MbscCalendarEvent[]>([]);
const [myCalendars, setCalendars] = useState<Array<{ name: string; id: number }>>([]);
const [calendarIds, setCalendarIds] = useState<string[]>([]);
const [calendarData, setCalendarData] = useState<{ [key: string]: { checked: boolean; color: string; name: string } }>({});
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
const [editable, setEditable] = useState<boolean>(false);
const [isLoading, setLoading] = useState<boolean>(false);
const [primaryCalendarId, setPrimaryCalendarId] = useState<string>('');
const [toastMessage, setToastMessage] = useState<string>('');
const [isToastOpen, setToastOpen] = useState<boolean>(false);
const [confirmEvent, setConfirmEvent] = useState<MbscCalendarEvent>();
const [confirmOldEvent, setConfirmOldEvent] = useState<MbscCalendarEvent>();
const [isUpdateConfirmOpen, setUpdateConfirmOpen] = useState(false);
const [isDeleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
const debounce = useRef<ReturnType<typeof setTimeout>>(undefined);
const startDate = useRef<Date>(null);
const endDate = useRef<Date>(null);
const view = useMemo<MbscEventcalendarView>(() => ({ calendar: { labels: true } }), []);
const onError = useCallback((resp: { message: string }) => {
setToastMessage(resp.message);
setToastOpen(true);
}, []);
const extendDefaultEvent = useCallback(
() => ({
color: calendarData[primaryCalendarId].color,
}),
[calendarData, primaryCalendarId],
);
useEffect(() => {
const onSignedIn = () => {
setIsLoggedIn(true);
outlookCalendarSync
.getCalendars()
.then((calendars) => {
calendars.sort((c: { isDefaultCalendar: boolean }) => (c.isDefaultCalendar ? -1 : 1));
const calData: { [key: string]: { name: string; color: string; checked: boolean } } = {};
const primaryCalId = calendars[0].id;
for (const c of calendars) {
calData[c.id] = { name: c.name, color: c.hexColor, checked: c.id === primaryCalId };
}
setCalendarIds([primaryCalId]);
setPrimaryCalendarId(primaryCalId);
setCalendarData(calData);
setCalendars(calendars);
setLoading(true);
return outlookCalendarSync.getEvents([primaryCalId], startDate.current!, endDate.current!);
})
.then((events) => {
setEvents(events);
setLoading(false);
})
.catch(onError);
};
const onSignedOut = () => {
setIsLoggedIn(false);
setCalendars([]);
setCalendarIds([]);
setCalendarData({});
setEvents([]);
};
// Init outlook client
outlookCalendarSync.init({
clientId: '<YOUR_OUTLOOK_CLIENT_ID>',
redirectUri: '<YOUR_OUTLOOK_REDIRECT_URI>',
onSignedIn: onSignedIn,
onSignedOut: onSignedOut,
});
}, [onError]);
const signIn = useCallback(() => {
outlookCalendarSync.signIn().catch(onError);
}, [onError]);
const signOut = useCallback(() => {
outlookCalendarSync.signOut().catch(onError);
}, [onError]);
const toggleEditing = useCallback((ev: ChangeEvent<HTMLInputElement>) => {
setEditable(ev.target.checked);
}, []);
const toggleCalendar = useCallback(
(ev: ChangeEvent<HTMLInputElement>) => {
const checked = ev.target.checked;
const calendarId = ev.target.value;
const updatedCalendarData = { ...calendarData, [calendarId]: { ...calendarData[calendarId], checked } };
setCalendarData(updatedCalendarData);
if (checked) {
setLoading(true);
setCalendarIds((calIds) => [...calIds, calendarId]);
outlookCalendarSync
.getEvents([calendarId], startDate.current!, endDate.current!)
.then((events) => {
setLoading(false);
setEvents((oldEvents) => [...oldEvents, ...events]);
})
.catch(onError);
} else {
setCalendarIds((calIds) => calIds.filter((item) => item !== calendarId));
setEvents((oldEvents) => oldEvents.filter((item) => item.outlookCalendarId !== calendarId));
}
},
[calendarData, onError],
);
const renderMyHeader = useCallback(
() => (
<>
<CalendarNav />
<div className="md-spinner">
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
<div className="md-spinner-blade"></div>
</div>
<div className="md-outlook-calendar-header">
<CalendarPrev />
<CalendarToday />
<CalendarNext />
</div>
</>
),
[],
);
const onPageLoading = useCallback(
(args: MbscPageLoadingEvent) => {
clearTimeout(debounce.current);
startDate.current = args.viewStart;
endDate.current = args.viewEnd;
debounce.current = setTimeout(() => {
if (outlookCalendarSync.isSignedIn()) {
setLoading(true);
outlookCalendarSync
.getEvents(calendarIds, startDate.current!, endDate.current!)
.then((events) => {
setLoading(false);
setEvents(events);
})
.catch(onError);
}
}, 200);
},
[calendarIds, onError],
);
const onEventCreate = useCallback(
(args: MbscEventCreateEvent) => {
if (outlookCalendarSync.isSignedIn()) {
const event = args.event;
outlookCalendarSync
.addEvent(primaryCalendarId, event)
.then((newEvent) => {
newEvent.color = event.color;
setEvents((oldEvents) => [...oldEvents, newEvent]);
setToastMessage('Event created in "' + calendarData[primaryCalendarId].name + '" calendar');
setToastOpen(true);
})
.catch((error) => {
setEvents((oldEvents) => [...oldEvents]);
onError(error);
});
}
},
[calendarData, onError, primaryCalendarId],
);
const onEventUpdate = useCallback((args: MbscEventUpdateEvent) => {
if (outlookCalendarSync.isSignedIn()) {
setConfirmEvent(args.event);
setConfirmOldEvent(args.oldEvent);
setUpdateConfirmOpen(true);
}
}, []);
const onEventDelete = useCallback((args: MbscEventDeleteEvent) => {
if (outlookCalendarSync.isSignedIn()) {
setConfirmEvent(args.event);
setDeleteConfirmOpen(true);
}
return false;
}, []);
const handleUpdateConfirmClose = useCallback(
(result: boolean) => {
if (result) {
const calendarId = confirmEvent!.outlookCalendarId;
outlookCalendarSync
.updateEvent(calendarId, confirmEvent!)
.then(() => {
setToastMessage('Event updated on "' + calendarData[calendarId].name + '" calendar');
setToastOpen(true);
})
.catch((error) => {
setEvents((oldEvents) => [...oldEvents.filter((item) => item.id !== confirmEvent!.id), confirmOldEvent!]);
onError(error);
});
} else {
setEvents((oldEvents) => [...oldEvents.filter((item) => item.id !== confirmEvent!.id), confirmOldEvent!]);
}
setUpdateConfirmOpen(false);
},
[calendarData, confirmEvent, confirmOldEvent, onError],
);
const handleDeleteConfirmClose = useCallback(
(result: boolean) => {
if (result) {
const calendarId = confirmEvent!.outlookCalendarId;
outlookCalendarSync
.deleteEvent(calendarId, confirmEvent!)
.then(() => {
setEvents((oldEvents) => oldEvents.filter((item) => item.id !== confirmEvent!.id));
setToastMessage('Event deleted from "' + calendarData[calendarId].name + '" calendar');
setToastOpen(true);
})
.catch(onError);
}
setDeleteConfirmOpen(false);
},
[calendarData, confirmEvent, onError],
);
const handleCloseToast = useCallback(() => setToastOpen(false), []);
return (
<Page className="md-sync-events-outlook-cont">
<div className="md-sync-events-outlook-menu">
{isLoggedIn ? (
<div>
<div className="mbsc-form-group-inset mbsc-align-center">
<p className="mbsc-italic mbsc-txt-muted">
Editing events sync back to your calendar when enabled. You'll be asked for confirmation on every action.
</p>
</div>
<div className="mbsc-form-group-inset">
<Switch label="Enable editing" checked={editable} onChange={toggleEditing} />
</div>
<div className="mbsc-form-group-inset md-sync-events-outlook-inset">
<div className="mbsc-form-group-title">My Calendars</div>
{myCalendars.map((cal: { name: string; id: number }) => (
<Switch label={cal.name} key={cal.id} value={cal.id} checked={calendarData[cal.id].checked} onChange={toggleCalendar} />
))}
</div>
<div className="mbsc-form-group-inset">
<Button className="md-sync-events-outlook-button mbsc-button-block" onClick={signOut}>
Log out of my account
</Button>
</div>
</div>
) : (
<div>
<div className="mbsc-form-group-inset mbsc-align-center">
<p className="mbsc-italic mbsc-txt-muted">Log into your Outlook account to view and edit your Outlook Calendar events</p>
<Button className="md-sync-events-outlook-button mbsc-button-block" onClick={signIn}>
Sync my outlook calendars
</Button>
</div>
</div>
)}
</div>
<div className={'md-sync-events-outlook-calendar ' + (isLoading ? 'md-loading-events' : '')}>
<div className="md-sync-events-overlay"></div>
<Eventcalendar
view={view}
data={myEvents}
exclusiveEndDates={true}
clickToCreate={editable}
dragToCreate={editable}
dragToMove={editable}
dragToResize={editable}
extendDefaultEvent={extendDefaultEvent}
renderHeader={renderMyHeader}
onPageLoading={onPageLoading}
onEventCreate={onEventCreate}
onEventUpdate={onEventUpdate}
onEventDelete={onEventDelete}
></Eventcalendar>
</div>
<Toast message={toastMessage} isOpen={isToastOpen} onClose={handleCloseToast} />
<Confirm
isOpen={isUpdateConfirmOpen}
title="Are you sure you want to update this event?"
message="This action will affect your Outlook Calendar event."
okText="Update"
onClose={handleUpdateConfirmClose}
/>
<Confirm
isOpen={isDeleteConfirmOpen}
title="Are you sure you want to delete this event?"
message="This action will remove the event from your Outlook Calendar as well."
okText="Delete"
onClose={handleDeleteConfirmClose}
/>
</Page>
);
};
export default App;
.md-sync-events-outlook-cont.mbsc-page {
display: flex;
height: 600px;
}
.md-sync-events-outlook-menu {
flex: 0 0 350px;
height: 100%;
overflow: auto;
}
.md-sync-events-outlook-calendar {
flex: 1 1 auto;
border-left: 1px solid #ccc;
}
.md-outlook-calendar-header {
flex: 1 0 auto;
display: flex;
justify-content: flex-end;
}
.md-sync-events-outlook-button.mbsc-button {
text-transform: capitalize;
}
.md-sync-events-outlook-inset {
margin-bottom: 0;
}
@media (max-width: 800px) {
.md-sync-events-outlook-cont.mbsc-page {
display: block;
height: auto;
}
}
/* loading spinner and overlay */
.md-loading-events .md-sync-events-overlay {
position: absolute;
z-index: 2;
top: 0;
right: 0;
bottom: 0;
left: 0;
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
.md-spinner {
visibility: hidden;
position: relative;
width: 20px;
height: 20px;
}
.md-loading-events .md-spinner {
visibility: visible;
}
.md-spinner .md-spinner-blade {
position: absolute;
left: 44.5%;
top: 37%;
width: 10%;
height: 25%;
border-radius: 50%/20%;
background-color: #8c8c8c;
-webkit-animation: md-spinner-fade 1s linear infinite;
animation: md-spinner-fade 1s linear infinite;
-webkit-animation-play-state: paused;
animation-play-state: paused;
}
.md-spinner .md-spinner-blade:nth-child(1) {
-webkit-animation-delay: -1.66667s;
animation-delay: -1.66667s;
-webkit-transform: rotate(30deg) translate(0, -150%);
transform: rotate(30deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(2) {
-webkit-animation-delay: -1.58333s;
animation-delay: -1.58333s;
-webkit-transform: rotate(60deg) translate(0, -150%);
transform: rotate(60deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(3) {
-webkit-animation-delay: -1.5s;
animation-delay: -1.5s;
-webkit-transform: rotate(90deg) translate(0, -150%);
transform: rotate(90deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(4) {
-webkit-animation-delay: -1.41667s;
animation-delay: -1.41667s;
-webkit-transform: rotate(120deg) translate(0, -150%);
transform: rotate(120deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(5) {
-webkit-animation-delay: -1.33333s;
animation-delay: -1.33333s;
-webkit-transform: rotate(150deg) translate(0, -150%);
transform: rotate(150deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(6) {
-webkit-animation-delay: -1.25s;
animation-delay: -1.25s;
-webkit-transform: rotate(180deg) translate(0, -150%);
transform: rotate(180deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(7) {
-webkit-animation-delay: -1.16667s;
animation-delay: -1.16667s;
-webkit-transform: rotate(210deg) translate(0, -150%);
transform: rotate(210deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(8) {
-webkit-animation-delay: -1.08333s;
animation-delay: -1.08333s;
-webkit-transform: rotate(240deg) translate(0, -150%);
transform: rotate(240deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(9) {
-webkit-animation-delay: -1s;
animation-delay: -1s;
-webkit-transform: rotate(270deg) translate(0, -150%);
transform: rotate(270deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(10) {
-webkit-animation-delay: -0.91667s;
animation-delay: -0.91667s;
-webkit-transform: rotate(300deg) translate(0, -150%);
transform: rotate(300deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(11) {
-webkit-animation-delay: -0.83333s;
animation-delay: -0.83333s;
-webkit-transform: rotate(330deg) translate(0, -150%);
transform: rotate(330deg) translate(0, -150%);
}
.md-spinner .md-spinner-blade:nth-child(12) {
-webkit-animation-delay: -0.75s;
animation-delay: -0.75s;
-webkit-transform: rotate(360deg) translate(0, -150%);
transform: rotate(360deg) translate(0, -150%);
}
.md-loading-events .md-spinner-blade {
-webkit-animation-play-state: running;
animation-play-state: running;
}
@-webkit-keyframes md-spinner-fade {
0% {
opacity: 0.85;
}
50% {
opacity: 0.25;
}
100% {
opacity: 0.25;
}
}
@keyframes md-spinner-fade {
0% {
opacity: 0.85;
}
50% {
opacity: 0.25;
}
100% {
opacity: 0.25;
}
}