---
title: "Vue Popup Event creation modal Example | Mobiscroll"
component: "Popup"
framework: "Vue"
library_version: "6.2.0"
url: "https://demo.mobiscroll.com/vue/popup/add-event-modal"
---

# Event creation modal - Vue Popup demo

Use the Vue popup for event add/edit modals. Trigger within the event calendar component and load your own custom forms. For Vue and Nuxt.

- [Live demo](https://demo.mobiscroll.com/vue/popup/add-event-modal)
- [View SFC JS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue/tree/main/src/demos/pickers/popup/add-event-modal)
- [View SFC TS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue-ts/tree/main/src/demos/pickers/popup/add-event-modal)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/popup/add-event-modal.md), [jQuery](https://demo.mobiscroll.com/jquery/popup/add-event-modal.md), [Angular](https://demo.mobiscroll.com/angular/popup/add-event-modal.md), [React](https://demo.mobiscroll.com/react/popup/add-event-modal.md)

## Description

Use the popup to show a modal with an add/edit form for event creation and/or update. The popup can be easily set up to be shown right in the middle of the screen, top, bottom or anchored to the newly added event. Check out the [different display modes](https://demo.mobiscroll.com/vue/popup/mobile-desktop-display) and play around with the different configurations.

You have full control over what is shown within the popup. Use [Mobiscroll form elements](https://demo.mobiscroll.com/vue/forms) or any components that you are already using throughout your application.

**Interested in exploring the event calendar?** [Check out these examples →](https://demo.mobiscroll.com/vue/eventcalendar)

## What this demo shows

- Shows a full month calendar which displays events with a custom `Add new event` button above it.
- **Event creation** Clicking `Add new event` opens a popup containing an event form.
- **Event editing** The same popup supports updating an existing event.
- **Event form** The editor includes fields for the title, description, all-day setting, start and end dates, travel time, event color, and busy or free status.
- **Date selection** The start and end date inputs open a date picker with range selection.
- **Save and close behavior** Clicking outside the popup or selecting Cancel closes the editor without applying changes. Selecting Save applies the event changes.
- **Delete flow** The edit dialog includes a `Delete event` action that removes the event from the calendar.
- **Responsive behavior** The dialog adapts to the screen size and device type, with touch-optimized controls such as scrollers on smaller screens and touch devices.
- **Mobile presentation** On smaller screens, the dialog appears as a sheet instead of a popover.
- **Day cell states** Hovering over a day cell highlights the day number with a gray background. Clicking an empty area of the cell selects the day and highlights the day number with a blue background.

## Best for

- **Appointment scheduling** Collect event details, dates, travel time, and availability in a dedicated creation and editing form.
- **Field service calendars** Capture travel time and job details when scheduling work across different locations.
- **Team calendars** Use event colors and busy or free status to communicate event types and availability.
- **Responsive scheduling interfaces** Present the same event workflow as a popover on larger screens and a touch-friendly sheet on smaller screens.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/vue/popup/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/vue/popup/api#opt-themeVariant) - option
- [`width`](https://mobiscroll.com/docs/vue/popup/api#opt-width) - option
- [`headerText`](https://mobiscroll.com/docs/vue/popup/api#opt-headerText) - option
- [`display`](https://mobiscroll.com/docs/vue/popup/api#opt-display) - option
- [`isOpen`](https://mobiscroll.com/docs/vue/popup/api#opt-isOpen) - option
- [`buttons`](https://mobiscroll.com/docs/vue/popup/api#opt-buttons) - option
- [`close`](https://mobiscroll.com/docs/vue/popup/api#event-onClose) - event
- [`select`](https://mobiscroll.com/docs/vue/datepicker/api#opt-select) - option
- [`touchUi`](https://mobiscroll.com/docs/vue/datepicker/api#opt-touchUi) - option
- [`display`](https://mobiscroll.com/docs/vue/datepicker/api#opt-display) - option
- [`controls`](https://mobiscroll.com/docs/vue/datepicker/api#opt-controls) - option
- [`startInput`](https://mobiscroll.com/docs/vue/datepicker/api#opt-startInput) - option
- [`endInput`](https://mobiscroll.com/docs/vue/datepicker/api#opt-endInput) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/vue/datepicker/api#opt-showRangeLabels) - option
- [`isOpen`](https://mobiscroll.com/docs/vue/notifications/toast#opt-isOpen) - option
- [`close`](https://mobiscroll.com/docs/vue/notifications/toast#event-onClose) - event
- [`selectedDate`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-selectedDate) - option
- [`data`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-data) - option

## Code

### SFC JS

```vue
<script setup>
import {
  MbscButton,
  MbscDatepicker,
  MbscEventcalendar,
  MbscInput,
  MbscPage,
  MbscPopup,
  MbscSegmented,
  MbscSegmentedGroup,
  MbscSwitch,
  MbscTextarea,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import { ref } from 'vue'

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

const myEvents = ref([
  {
    id: 1,
    start: '2026-10-08T13:00',
    end: '2026-10-08T13:45',
    title: "Lunch @ Butcher's",
    description: '',
    allDay: false,
    bufferBefore: 15,
    free: true,
    color: '#009788'
  },
  {
    id: 2,
    start: '2026-10-31T15:00',
    end: '2026-10-31T16:00',
    title: 'Conference',
    description: '',
    allDay: false,
    bufferBefore: 30,
    free: false,
    color: '#ff9900'
  },
  {
    id: 3,
    start: '2026-10-30T18:00',
    end: '2026-10-30T22:00',
    title: 'Site Visit',
    description: '',
    allDay: false,
    bufferBefore: 60,
    free: true,
    color: '#3f51b5'
  },
  {
    id: 4,
    start: '2026-11-01T10:30',
    end: '2026-11-01T11:30',
    title: 'Stakeholder mtg.',
    description: '',
    allDay: false,
    free: false,
    color: '#f44437'
  }
])

const mySelectedDate = ref(new Date())
const isPopupOpen = ref(false)
const popupEventAllDay = ref(false)
const datePickerControls = ['calendar']
const datetimePickerControls = ['calendar', 'time']
const popupEventTitle = ref('')
const popupEventDescription = ref('')
const popupEventDates = ref([new Date(), new Date()])
const popupEventStatus = ref('free')

const toastMessage = ref('Event added')
const isToastOpen = ref(false)

const startInput = ref(null)
const endInput = ref(null)

function openPopup() {
  popupEventTitle.value = 'New Event'
  isPopupOpen.value = true
}
</script>

<template>
  <MbscPage>
    <div class="mbsc-form-group">
      <div class="mbsc-button-group-block">
        <MbscButton @click="openPopup">Add event</MbscButton>
      </div>
    </div>

    <MbscPopup
      :width="400"
      :contentPadding="false"
      headerText="Add new event"
      display="center"
      :isOpen="isPopupOpen"
      :buttons="[
        'cancel',
        {
          text: 'Add',
          keyCode: 'enter',
          handler: function () {
            const newEvent = {
              title: popupEventTitle,
              description: popupEventDescription,
              allDay: popupEventAllDay,
              status: popupEventStatus,
              start: popupEventDates[0],
              end: popupEventDates[1]
            }

            myEvents = [...myEvents, newEvent]
            mySelectedDate = popupEventDates[0]

            isPopupOpen = false
            isToastOpen = true
          },
          cssClass: 'mbsc-popup-button-primary'
        }
      ]"
      @close="isPopupOpen = false"
    >
      <div class="mbsc-form-group">
        <MbscInput label="Title" v-model="popupEventTitle" />
        <MbscTextarea label="Description" v-model="popupEventDescription" />
      </div>
      <div class="mbsc-form-group">
        <MbscSwitch label="All-day" v-model="popupEventAllDay" />

        <MbscInput ref="startInput" label="Starts" />
        <MbscInput ref="endInput" label="Ends" />

        <MbscDatepicker
          v-model="popupEventDates"
          select="range"
          :touchUi="true"
          display="anchored"
          :controls="popupEventAllDay ? datePickerControls : datetimePickerControls"
          :startInput="startInput"
          :endInput="endInput"
          :showRangeLabels="false"
        />
        <MbscSegmentedGroup v-model="popupEventStatus">
          <MbscSegmented value="busy">Show as busy</MbscSegmented>
          <MbscSegmented value="free">Show as free</MbscSegmented>
        </MbscSegmentedGroup>
        <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="isToastOpen = false" />
      </div>
    </MbscPopup>
    <MbscEventcalendar :selectedDate="mySelectedDate" :data="myEvents"> </MbscEventcalendar>
  </MbscPage>
</template>
```

### SFC TS

```vue
<script setup lang="ts">
import {
  MbscButton,
  MbscDatepicker,
  MbscEventcalendar,
  MbscInput,
  MbscPage,
  MbscPopup,
  MbscSegmented,
  MbscSegmentedGroup,
  MbscSwitch,
  MbscTextarea,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import type { MbscCalendarEvent } from '@mobiscroll/vue'
import { ref } from 'vue'

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

const myEvents = ref<MbscCalendarEvent[]>([
  {
    id: 1,
    start: '2026-10-08T13:00',
    end: '2026-10-08T13:45',
    title: "Lunch @ Butcher's",
    description: '',
    allDay: false,
    bufferBefore: 15,
    free: true,
    color: '#009788'
  },
  {
    id: 2,
    start: '2026-10-31T15:00',
    end: '2026-10-31T16:00',
    title: 'Conference',
    description: '',
    allDay: false,
    bufferBefore: 30,
    free: false,
    color: '#ff9900'
  },
  {
    id: 3,
    start: '2026-10-30T18:00',
    end: '2026-10-30T22:00',
    title: 'Site Visit',
    description: '',
    allDay: false,
    bufferBefore: 60,
    free: true,
    color: '#3f51b5'
  },
  {
    id: 4,
    start: '2026-11-01T10:30',
    end: '2026-11-01T11:30',
    title: 'Stakeholder mtg.',
    description: '',
    allDay: false,
    free: false,
    color: '#f44437'
  }
])

const mySelectedDate = ref<Date>(new Date())
const isPopupOpen = ref<boolean>(false)
const popupEventAllDay = ref<boolean>(false)
const datePickerControls: any = ['calendar']
const datetimePickerControls: any = ['calendar', 'time']
const popupEventTitle = ref<string>('')
const popupEventDescription = ref<string>('')
const popupEventDates = ref<Date[]>([new Date(), new Date()])
const popupEventStatus = ref<'free' | 'busy'>('free')
const toastMessage = ref<string>('Event added')
const isToastOpen = ref<boolean>(false)

const startInput = ref<any>(null)
const endInput = ref<any>(null)

function openPopup() {
  popupEventTitle.value = 'New Event'
  isPopupOpen.value = true
}
</script>

<template>
  <MbscPage>
    <div class="mbsc-form-group">
      <div class="mbsc-button-group-block">
        <MbscButton @click="openPopup">Add event</MbscButton>
      </div>
    </div>

    <MbscPopup
      :width="400"
      :contentPadding="false"
      headerText="Add new event"
      display="center"
      :isOpen="isPopupOpen"
      :buttons="[
        'cancel',
        {
          text: 'Add',
          keyCode: 'enter',
          handler: function () {
            const newEvent = {
              title: popupEventTitle,
              description: popupEventDescription,
              allDay: popupEventAllDay,
              status: popupEventStatus,
              start: popupEventDates[0],
              end: popupEventDates[1]
            }

            myEvents = [...myEvents, newEvent]
            mySelectedDate = popupEventDates[0]

            isPopupOpen = false
            isToastOpen = true
          },
          cssClass: 'mbsc-popup-button-primary'
        }
      ]"
      @close="isPopupOpen = false"
    >
      <div class="mbsc-form-group">
        <MbscInput label="Title" v-model="popupEventTitle" />
        <MbscTextarea label="Description" v-model="popupEventDescription" />
      </div>
      <div class="mbsc-form-group">
        <MbscSwitch label="All-day" v-model="popupEventAllDay" />

        <MbscInput ref="startInput" label="Starts" />
        <MbscInput ref="endInput" label="Ends" />

        <MbscDatepicker
          v-model="popupEventDates"
          select="range"
          :touchUi="true"
          display="anchored"
          :controls="popupEventAllDay ? datePickerControls : datetimePickerControls"
          :startInput="startInput"
          :endInput="endInput"
          :showRangeLabels="false"
        />
        <MbscSegmentedGroup v-model="popupEventStatus">
          <MbscSegmented value="busy">Show as busy</MbscSegmented>
          <MbscSegmented value="free">Show as free</MbscSegmented>
        </MbscSegmentedGroup>
        <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="isToastOpen = false" />
      </div>
    </MbscPopup>
    <MbscEventcalendar :selectedDate="mySelectedDate" :data="myEvents"> </MbscEventcalendar>
  </MbscPage>
</template>
```

## Implementation notes

- `Popup` renders arbitrary content as children; the demo places `mbsc-form-group` blocks containing an `Input` (Title), an `Input`/`Textarea` (Description), a `Switch` (All-day), two more `Input`s (Starts/Ends) used as `startInput`/`endInput` for the date picker, and a `SegmentedGroup` with two segments (Show as busy/free).
- `width: 400`, `contentPadding: false`, `headerText: 'Add new event'`, `display: 'center'`, and `showOverlay: false` configure a fixed-width, centered popup with a header title, no default inner padding (so the form controls its own spacing), and no dimmed backdrop.
- `buttons` combines a plain `'cancel'` string entry with a custom button object - `{ text: 'Add', keyCode: 'enter', handler, cssClass: 'mbsc-popup-button-primary' }` - so pressing Enter or clicking the button runs `handler` (builds the new event from form state, appends it to the events array/data source, closes the popup, and shows a toast) without a separate `set`/`ok` default action.
- The nested `Datepicker` uses `select: 'range'`, `display: 'anchored'`, `touchUi: true`, and `showRangeLabels: false`; its `controls` toggles between `['calendar']` (all-day) and `['calendar', 'time']` (timed) based on the `Switch`'s checked state - in React/Vue this is a derived value recomputed on render/`v-model`; in Angular/JS it's reassigned via `[controls]` binding or `.setOptions({ controls })` in the `Switch`'s change handler.
- The date picker is wired to the two `Input`s via `startInput`/`endInput` (`[startInput]`/`[endInput]` in Angular, `:startInput`/`:endInput` in Vue, refs passed as props in React, element IDs as strings in JS/jQuery) so typing or picking updates those fields instead of rendering its own text field.
- Opening the popup is imperative in JS/jQuery and Angular, declarative in React/Vue: JS captures the popup instance directly from the return value of `mobiscroll.popup(...)`; jQuery instead calls `.mobiscroll('getInst')` on the popup element to get it; either way, the trigger button's click handler then resets all the field instances' values/checked state and calls `.open()`; Angular keeps a `@ViewChild` reference (`popup: MbscPopup`), resets the component's bound fields, and calls `popup.open()`; React and Vue instead bind the popup's `isOpen`/`:isOpen` prop to state that the trigger button's click handler resets and sets to `true`, and reset that state through an `onClose`/`@close` callback (or the custom Add button's `handler`).
- The `Eventcalendar`'s `data`/event array is updated by spreading in the new event object built inside the Add button's `handler`; `selectedDate` is then set to the new event's `start` so the calendar navigates to it (JS/jQuery instead call `calendar.addEvent(newEvent)` and `calendar.navigateToEvent(newEvent)` on the `Eventcalendar` instance).

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-vue.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config vue
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config vue --trial`.

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

- Next: [Using as a tooltip](https://demo.mobiscroll.com/vue/popup/show-hide-tooltip-hover-in-out.md) - Use the Vue popup with custom content on event hover within the various event calendar views.
