---
title: "Vue Forms Inside a modal Example | Mobiscroll"
component: "Forms"
framework: "Vue"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/vue/forms/popup"
---

# Inside a modal - Vue Forms demo

Vue embedded forms in modal or pop-over. Perfect layout for contextual add/edit forms. For Vue and Nuxt.

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

## Description

When working with the [event calendar](https://demo.mobiscroll.com/vue/eventcalendar) you will usually want to show an add/edit form in a popup rather than render it directly into the page markup. Simply configure the popup and add your form fields to it.

**Interested in add/edit screens for events?** [Check out this example of a fully functional event form →](https://demo.mobiscroll.com/vue/eventcalendar/create-read-update-delete-CRUD)

## What this demo shows

- This demo shows a modal form which opens a responsive popup form from a button.
- **Form fields** Includes fields for the title, description, start date, and end date.
- **All-day setting** Uses a toggle to switch between timed and all-day entries.
- **Availability** Uses a segmented control to mark the entry as busy or free.
- **Form actions** Provides Cancel and Set actions for dismissing or confirming the form.
- **Responsive layout** Combines multiple form controls within a modal interface that adapts to the available screen size.

## Best for

- **Calendar event forms** Create or edit event details without navigating away from the calendar.
- **Appointment scheduling** Collect a title, notes, timing, and availability in a focused popup workflow.
- **Availability management** Let users define timed or all-day availability and mark it as busy or free.
- **Compact data entry** Keep short forms accessible from the current page while preserving the surrounding context.
- **Responsive workflows** Present the same modal form across desktop and mobile layouts.

## Tutorial

```vue
<script setup>
const popupOpen = ref(false)
const popupAnchor = ref(null)
const popupButtons = ['set', 'cancel']

function handleClick(ev) {
  popupAnchor.value = ev.target
  popupOpen.value = true
}

function handleClose() {
  popupOpen.value = false
}
</script>

<template>
  <MbscButton @click="handleClick">Show modal</MbscButton>
  <MbscPopup
    display="anchored"
    :isOpen="popupOpen"
    :anchor="popupAnchor"
    :buttons="popupButtons"
    :contentPadding="false"
    @close="handleClose"
  >
    <div class="mbsc-form-group">
      <MbscInput label="Title" />
      <MbscTextarea label="Description" />
    </div>
    <div class="mbsc-form-group">
      <MbscSwitch label="All-day" />
      <MbscInput label="Starts" />
      <MbscInput label="Ends" />
      <MbscSegmentedGroup>
        <MbscSegmented  :defaultChecked="true">Show as busy</MbscSegmented>
        <MbscSegmented>Show as free</MbscSegmented>
      </MbscSegmentedGroup>
    </div>
  </MbscPopup>
</template>
```

## API used in this demo

- [`display`](https://mobiscroll.com/docs/vue/popup/api#opt-display) - option
- [`width`](https://mobiscroll.com/docs/vue/popup/api#opt-width) - option
- [`fullScreen`](https://mobiscroll.com/docs/vue/popup/api#opt-fullScreen) - option
- [`touchUi`](https://mobiscroll.com/docs/vue/popup/api#opt-touchUi) - option
- [`isOpen`](https://mobiscroll.com/docs/vue/popup/api#opt-isOpen) - option
- [`anchor`](https://mobiscroll.com/docs/vue/popup/api#opt-anchor) - option
- [`buttons`](https://mobiscroll.com/docs/vue/popup/api#opt-buttons) - option
- [`responsive`](https://mobiscroll.com/docs/vue/popup/api#opt-responsive) - option
- [`close`](https://mobiscroll.com/docs/vue/popup/api#event-onClose) - event

## Code

### SFC JS

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

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

const popupOpen = ref(false)
const popupAnchor = ref(null)
const popupButtons = ['set', 'cancel']
const popupResponsive = {
  medium: {
    display: 'anchored',
    width: 400,
    fullScreen: false,
    touchUi: false
  }
}

function handleClick(ev) {
  popupAnchor.value = ev.target
  popupOpen.value = true
}

function handleClose() {
  popupOpen.value = false
}
</script>

<template>
  <MbscPage>
    <MbscButton @click="handleClick">Show modal</MbscButton>
    <MbscPopup
      display="anchored"
      :isOpen="popupOpen"
      :anchor="popupAnchor"
      :buttons="popupButtons"
      :contentPadding="false"
      :responsive="popupResponsive"
      @close="handleClose"
    >
      <div class="mbsc-form-group">
        <MbscInput label="Title" />
        <MbscTextarea label="Description" />
      </div>
      <div class="mbsc-form-group">
        <MbscSwitch label="All-day" />
        <MbscInput label="Starts" />
        <MbscInput label="Ends" />
        <MbscSegmentedGroup>
          <MbscSegmented :defaultChecked="true">Show as busy</MbscSegmented>
          <MbscSegmented>Show as free</MbscSegmented>
        </MbscSegmentedGroup>
      </div>
    </MbscPopup>
  </MbscPage>
</template>
```

### SFC TS

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

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

const popupOpen = ref<boolean>(false)
const popupAnchor = ref<any>(null)
const popupButtons = ['set', 'cancel']
const popupResponsive: MbscResponsiveOptions<MbscPopupOptions> = {
  medium: {
    display: 'anchored',
    width: 400,
    fullScreen: false,
    touchUi: false
  }
}

function handleClick(ev: any) {
  popupAnchor.value = ev.target
  popupOpen.value = true
}

function handleClose() {
  popupOpen.value = false
}
</script>

<template>
  <MbscPage>
    <MbscButton @click="handleClick">Show modal</MbscButton>
    <MbscPopup
      display="anchored"
      :isOpen="popupOpen"
      :anchor="popupAnchor"
      :buttons="popupButtons"
      :contentPadding="false"
      :responsive="popupResponsive"
      @close="handleClose"
    >
      <div class="mbsc-form-group">
        <MbscInput label="Title" />
        <MbscTextarea label="Description" />
      </div>
      <div class="mbsc-form-group">
        <MbscSwitch label="All-day" />
        <MbscInput label="Starts" />
        <MbscInput label="Ends" />
        <MbscSegmentedGroup>
          <MbscSegmented :defaultChecked="true">Show as busy</MbscSegmented>
          <MbscSegmented>Show as free</MbscSegmented>
        </MbscSegmentedGroup>
      </div>
    </MbscPopup>
  </MbscPage>
</template>
```

## Implementation notes

- `Popup` renders arbitrary content as children; the demo places two `mbsc-form-group` blocks inside it containing an `Input` (Title), a `Textarea` (Description), a `Switch` (All-day), two more `Input`s (Starts/Ends), and a `SegmentedGroup` with two segments (Show as busy/free).
- `buttons: ['set', 'cancel']` renders Set/Cancel action buttons in the popup's footer.
- `display: 'anchored'` anchors the popup to a trigger element rather than centering it; `anchor` is the DOM element it positions against. In JS/jQuery, `anchor` is applied via `.setOptions({ anchor: event.target })` right before calling `.open()`; React/Vue bind it as an `anchor`/`:anchor` prop driven by state set to `event.target` on click.
- `contentPadding: false` removes the popup's default inner padding so the form fields control their own spacing.
- `fullScreen: true` makes the popup fill the screen; `responsive: { medium: { display: 'anchored', width: 400, fullScreen: false, touchUi: false } }` overrides `display`, `width`, `fullScreen`, and `touchUi` at the `medium` breakpoint so larger screens get a fixed-width anchored panel with desktop (non-touch) styling instead of the full-screen mobile layout.
- 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')` once on the popup element to get it; either way, the button's click handler then calls `.setOptions({ anchor: event.target })` followed by `.open()`; Angular keeps a `@ViewChild` reference (`inst: MbscPopup`), sets `popupSettings.anchor = event.target`, and calls `inst.open()`; React and Vue instead bind the popup's `isOpen`/`:isOpen` prop to state that the button's click handler sets to `true` (along with an `anchor`/`:anchor` state update), and reset that state through an `onClose`/`@close` callback.
- Inside the popup, the `Switch`'s checked state marks the entry as all-day; the two `Segmented` controls share a `name` so they behave as a mutually exclusive pair (`checked`/`defaultChecked` marks the default selection) recording busy/free availability.

## 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

- Previous: [Responsive form](https://demo.mobiscroll.com/vue/forms/responsive.md) - Responsive Vue form using grid layout. Define how the form elements behaves across multiple screen sizes.
