---
title: "Vue Agenda Load Public Google Calendar Events Example | Mobiscroll"
component: "Agenda"
framework: "Vue"
library_version: "6.2.0"
url: "https://demo.mobiscroll.com/vue/agenda/load-events-from-google-calendar"
---

# Load Public Google Calendar Events - Vue Agenda demo

Show public Google Calendar events in the Vue agenda view via the integration plugin — supply a Calendar ID and API key to connect. For Vue and Nuxt.

- [Live demo](https://demo.mobiscroll.com/vue/agenda/load-events-from-google-calendar)
- [View SFC JS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue/tree/main/src/demos/eventcalendar/agenda/load-events-from-google-calendar)
- [View SFC TS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue-ts/tree/main/src/demos/eventcalendar/agenda/load-events-from-google-calendar)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/agenda/load-events-from-google-calendar.md), [jQuery](https://demo.mobiscroll.com/jquery/agenda/load-events-from-google-calendar.md), [Angular](https://demo.mobiscroll.com/angular/agenda/load-events-from-google-calendar.md), [React](https://demo.mobiscroll.com/react/agenda/load-events-from-google-calendar.md)

## Description

Event data can be loaded from remote sources, like public google calendars. Through the [**integration plugin**](https://mobiscroll.com/docs/vue/eventcalendar/calendar-integrations) 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](https://demo.mobiscroll.com/vue/agenda/sync-events-google-calendar).

This example uses the [**integration plugin**](https://mobiscroll.com/docs/vue/eventcalendar/calendar-integrations) to connect to and load events from Google Calendar and it is not available in the trial. Give the live demo a try and see how it can be configured.

## What this demo shows

- Shows a weekly agenda view with events listed and grouped by date.
- **Custom header** The current month and year are shown on the left side of the header.
- **View switching** A segmented control in the center lets users switch between `Month`, `Week`, `Day`, and `Agenda` views, with `Agenda` selected by default.
- **Secondary navigation** Blue previous and next arrow buttons are shown on the right side of the header with a `Today` button between them.
- **Week view** A week calendar is displayed at the top of the view.
- **Week navigation** The week strip can be changed by clicking and dragging left or right.
- **Day cell states** Hovering a day highlights the day number with a gray background. Selecting a day highlights the day number with a blue background. The current date is highlighted by default.
- **Event markers** Days with events show a small dot marker inside the day cell.
- **Agenda list** The area below the calendar lists events for the selected day.
- **Date selection** Selecting a day in the week calendar updates the agenda to show events for that date.
- **Events** Events appear as agenda cards with a colored strip on the left and the event title next to it. Start and end times are stacked on the right side of timed events. All-day events show the all-day label on the right.
- **Event interaction** Hovering an event highlights it.
- **Event selection** Clicking an event selects and highlights it.
- **Weekly scheduler view** Selecting the `Week` option from the segmented control switches the layout to a weekly scheduler view. This shows the days of the week at the top, an all-day section for all-day events, and a 24-hour time grid for each day of the week for timed events.
- **Daily scheduler view** Selecting the `Day` option from the segmented control switches the layout to a daily scheduler view. This shows the days of the week at the top, an all-day section for all-day events, and a 24-hour time grid for one day for timed events.
- **Scheduler view** The current time is marked with a blue line in the time grid.
- **Scheduler view** The time grid can be scrolled vertically with the mouse wheel while the header stays sticky.
- **Monthly calendar view** Selecting the `Month` option from the segmented control switches the layout to a monthly calendar view. Days with events display event labels inside the month grid cells.

## Best for

- **Google Calendar overlays** Showing events from public Google Calendars inside an agenda view.
- **Read-only event publishing** Sharing team, organization, or community calendars where visitors need to browse events but not edit them.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-themeVariant) - option
- [`onInit`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onInit) - event
- [`data`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-data) - option
- [`exclusiveEndDates`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-exclusiveEndDates) - option
- [`view`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-view) - option
- [`page-loading`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onPageLoading) - event
- [`close`](https://mobiscroll.com/docs/vue/notifications/toast#event-onClose) - event

## Code

### SFC JS

```vue
<script setup>
import { googleCalendarSync } from '@mobiscroll/calendar-integration'
import {
  MbscCalendarNav,
  MbscCalendarNext,
  MbscCalendarPrev,
  MbscCalendarToday,
  MbscEventcalendar,
  MbscSegmented,
  MbscSegmentedGroup,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import { onMounted, ref } from 'vue'

setOptions({
  theme: 'ios',
  themeVariant: 'light'
})

const CALENDAR_ID = 'theacidmedia.net_8l6v679q5j2f7q8lpmcjr4mm3k@group.calendar.google.com'

const currentView = ref('agenda')
const isLoading = ref(false)
const isToastOpen = ref(false)
const myEvents = ref([])
const myView = ref({
  calendar: { type: 'week' },
  agenda: { type: 'week' }
})
const toastMessage = ref('')

const firstDay = ref()
const lastDay = ref()

function handleError(resp) {
  toastMessage.value = resp.error ? resp.error : resp.result.error.message
  isToastOpen.value = true
}

function loadEvents() {
  isLoading.value = true
  googleCalendarSync
    .getEvents(CALENDAR_ID, firstDay.value, lastDay.value)
    .then((resp) => {
      myEvents.value = resp
      isLoading.value = false
    })
    .catch(handleError)
}

function changeView() {
  switch (currentView.value) {
    case 'month':
      myView.value = {
        calendar: { type: 'month' }
      }
      break
    case 'week':
      myView.value = {
        scheduler: { type: 'week' }
      }
      break
    case 'day':
      myView.value = {
        scheduler: { type: 'day' }
      }
      break
    case 'agenda':
    default:
      myView.value = {
        calendar: { type: 'week' },
        agenda: { type: 'week' }
      }
      break
  }
}

function handlePageLoading(args) {
  const start = args.viewStart
  const end = args.viewEnd

  // Calculate dates
  // (pre-load events for previous and next pages as well)
  if (currentView.value === 'month') {
    firstDay.value = start
    lastDay.value = end
  } else {
    firstDay.value = new Date(start.getFullYear(), start.getMonth(), start.getDate() - 7)
    lastDay.value = new Date(end.getFullYear(), end.getMonth(), end.getDate() + 7)
  }

  loadEvents()
}

onMounted(() => {
  // Init google client
  googleCalendarSync.init({
    apiKey: '<YOUR_GOOGLE_API_KEY>',
    onInit: loadEvents
  })
})
</script>

<template>
  <MbscEventcalendar
    :data="myEvents"
    :exclusiveEndDates="true"
    :view="myView"
    @page-loading="handlePageLoading"
  >
    <template #header>
      <MbscCalendarNav className="mds-google-cal-nav" />
      <div :class="'mds-loader' + (isLoading ? ' mds-loader-visible' : '')"></div>
      <div class="mds-google-cal-switch mbsc-flex-1-0">
        <MbscSegmentedGroup v-model="currentView" @change="changeView">
          <MbscSegmented value="month"> Month </MbscSegmented>
          <MbscSegmented value="week"> Week </MbscSegmented>
          <MbscSegmented value="day"> Day </MbscSegmented>
          <MbscSegmented value="agenda"> Agenda </MbscSegmented>
        </MbscSegmentedGroup>
      </div>
      <MbscCalendarPrev className="mds-google-cal-prev" />
      <MbscCalendarToday className="mds-google-cal-today" />
      <MbscCalendarNext className="mds-google-cal-next" />
    </template>
  </MbscEventcalendar>
  <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="isToastOpen = false" />
</template>

<style>
.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;
}
</style>
```

### SFC TS

```vue
<script setup lang="ts">
import { googleCalendarSync } from '@mobiscroll/calendar-integration'
import {
  MbscCalendarNav,
  MbscCalendarNext,
  MbscCalendarPrev,
  MbscCalendarToday,
  MbscEventcalendar,
  MbscSegmented,
  MbscSegmentedGroup,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import type {
  MbscCalendarEvent,
  MbscEventcalendarView,
  MbscPageLoadingEvent
} from '@mobiscroll/vue'
import { onMounted, ref } from 'vue'

setOptions({
  theme: 'ios',
  themeVariant: 'light'
})

const CALENDAR_ID = 'theacidmedia.net_8l6v679q5j2f7q8lpmcjr4mm3k@group.calendar.google.com'

const currentView = ref<string>('agenda')
const isLoading = ref<boolean>(false)
const isToastOpen = ref<boolean>(false)
const myEvents = ref<MbscCalendarEvent[]>([])
const myView = ref<MbscEventcalendarView>({
  calendar: { type: 'week' },
  agenda: { type: 'week' }
})
const toastMessage = ref<string>('')

const firstDay = ref<Date>()
const lastDay = ref<Date>()

function handleError(resp: { error: string; result: { error: { message: string } } }) {
  toastMessage.value = resp.error ? resp.error : resp.result.error.message
  isToastOpen.value = true
}

function loadEvents() {
  isLoading.value = true
  googleCalendarSync
    .getEvents(CALENDAR_ID, firstDay.value!, lastDay.value!)
    .then((resp: MbscCalendarEvent[]) => {
      myEvents.value = resp
      isLoading.value = false
    })
    .catch(handleError)
}

function changeView() {
  switch (currentView.value) {
    case 'month':
      myView.value = {
        calendar: { type: 'month' }
      }
      break
    case 'week':
      myView.value = {
        scheduler: { type: 'week' }
      }
      break
    case 'day':
      myView.value = {
        scheduler: { type: 'day' }
      }
      break
    case 'agenda':
    default:
      myView.value = {
        calendar: { type: 'week' },
        agenda: { type: 'week' }
      }
      break
  }
}

function handlePageLoading(args: MbscPageLoadingEvent) {
  const start = args.viewStart!
  const end = args.viewEnd!

  // Calculate dates
  // (pre-load events for previous and next pages as well)
  if (currentView.value === 'month') {
    firstDay.value = start
    lastDay.value = end
  } else {
    firstDay.value = new Date(start.getFullYear(), start.getMonth(), start.getDate() - 7)
    lastDay.value = new Date(end.getFullYear(), end.getMonth(), end.getDate() + 7)
  }

  loadEvents()
}

onMounted(() => {
  // Init google client
  googleCalendarSync.init({
    apiKey: '<YOUR_GOOGLE_API_KEY>',
    onInit: loadEvents
  })
})
</script>

<template>
  <MbscEventcalendar
    :data="myEvents"
    :exclusiveEndDates="true"
    :view="myView"
    @page-loading="handlePageLoading"
  >
    <template #header>
      <MbscCalendarNav className="mds-google-cal-nav" />
      <div :class="'mds-loader' + (isLoading ? ' mds-loader-visible' : '')"></div>
      <div class="mds-google-cal-switch mbsc-flex-1-0">
        <MbscSegmentedGroup v-model="currentView" @change="changeView">
          <MbscSegmented value="month"> Month </MbscSegmented>
          <MbscSegmented value="week"> Week </MbscSegmented>
          <MbscSegmented value="day"> Day </MbscSegmented>
          <MbscSegmented value="agenda"> Agenda </MbscSegmented>
        </MbscSegmentedGroup>
      </div>
      <MbscCalendarPrev className="mds-google-cal-prev" />
      <MbscCalendarToday className="mds-google-cal-today" />
      <MbscCalendarNext className="mds-google-cal-next" />
    </template>
  </MbscEventcalendar>
  <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="isToastOpen = false" />
</template>

<style>
.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;
}
</style>
```

## Implementation notes

- Install the `@mobiscroll/calendar-integration` package. Call `googleCalendarSync.init({ apiKey: '<YOUR_GOOGLE_API_KEY>', onInit: loadEvents })` on mount to authenticate. Provide a `CALENDAR_ID` (the public Google Calendar ID).
- Set `exclusiveEndDates: true` on the Eventcalendar - Google Calendar uses exclusive end dates.
- Start with `view: { calendar: { type: 'week' }, agenda: { type: 'week' } }`. The view is switchable via a `SegmentedGroup` (Month / Week / Day / Agenda) in the custom header. On segment change, update the view: month → `{ calendar: { type: 'month' } }`, week → `{ scheduler: { type: 'week' } }`, day → `{ scheduler: { type: 'day' } }`, agenda → `{ calendar: { type: 'week' }, agenda: { type: 'week' } }`.
- Use `onPageLoading` to load events on every page change. Extract `args.viewStart` and `args.viewEnd` to determine the range. For non-month views, extend the range ±7 days to pre-load the previous and next pages. Call `googleCalendarSync.getEvents(CALENDAR_ID, firstDay, lastDay)` - it returns a Promise. On resolve, update the events array; on reject, show a Toast with the error message from `resp.error` or `resp.result.error.message`.
- Build a custom header using `renderHeader` (Angular: `headerTemplate`, Vue: `header` slot) containing: `CalendarNav`, a CSS loading spinner (toggle visibility while the Promise is pending), a `SegmentedGroup` for view switching, `CalendarPrev`, `CalendarToday`, `CalendarNext`.

## Run it in your project

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/vue/getting-started/installation

## Related demos

- Previous: [Outlook Calendar Sync](https://demo.mobiscroll.com/vue/agenda/sync-events-outlook-calendar.md) - Use the Vue event calendar integration plugin to authenticate users, load their Outlook calendars, and display events in an agenda view.
