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

# Event creation modal - React Popup demo

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

- [Live demo](https://demo.mobiscroll.com/react/popup/add-event-modal)
- [View React JS code on GitHub](https://github.com/acidb/mobiscroll-demos-react/tree/main/src/demos/pickers/popup/add-event-modal)
- [View React TS code on GitHub](https://github.com/acidb/mobiscroll-demos-react-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), [Vue](https://demo.mobiscroll.com/vue/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/react/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/react/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/react/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/react/popup/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/react/popup/api#opt-themeVariant) - option
- [`width`](https://mobiscroll.com/docs/react/popup/api#opt-width) - option
- [`headerText`](https://mobiscroll.com/docs/react/popup/api#opt-headerText) - option
- [`display`](https://mobiscroll.com/docs/react/popup/api#opt-display) - option
- [`showOverlay`](https://mobiscroll.com/docs/react/popup/api#opt-showOverlay) - option
- [`isOpen`](https://mobiscroll.com/docs/react/popup/api#opt-isOpen) - option
- [`buttons`](https://mobiscroll.com/docs/react/popup/api#opt-buttons) - option
- [`cssClass`](https://mobiscroll.com/docs/react/popup/api#opt-cssClass) - option
- [`onClose`](https://mobiscroll.com/docs/react/popup/api#event-onClose) - event
- [`select`](https://mobiscroll.com/docs/react/datepicker/api#opt-select) - option
- [`display`](https://mobiscroll.com/docs/react/datepicker/api#opt-display) - option
- [`controls`](https://mobiscroll.com/docs/react/datepicker/api#opt-controls) - option
- [`touchUi`](https://mobiscroll.com/docs/react/datepicker/api#opt-touchUi) - option
- [`startInput`](https://mobiscroll.com/docs/react/datepicker/api#opt-startInput) - option
- [`endInput`](https://mobiscroll.com/docs/react/datepicker/api#opt-endInput) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/react/datepicker/api#opt-showRangeLabels) - option
- [`onChange`](https://mobiscroll.com/docs/react/datepicker/api#event-onChange) - event
- [`data`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-data) - option
- [`selectedDate`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-selectedDate) - option
- [`isOpen`](https://mobiscroll.com/docs/react/notifications/toast#opt-isOpen) - option
- [`onClose`](https://mobiscroll.com/docs/react/notifications/toast#event-onClose) - event

## Code

### JSX

```jsx
import {
  Button,
  Datepicker,
  Eventcalendar,
  Input,
  Page,
  Popup,
  Segmented,
  SegmentedGroup,
  setOptions,
  Switch,
  Toast,
} from '@mobiscroll/react';
import { useCallback, useMemo, useState } from 'react';

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

function App() {
  const [isPopupOpen, setPopupOpen] = useState(false);
  const [popupEventAllDay, setAllDay] = useState(false);
  const [popupEventTitle, setTitle] = useState('');
  const [popupEventDescription, setDescription] = useState('');
  const [popupEventStatus, setStatus] = useState(false);
  const [popupEventDate, setDate] = useState([]);
  const [start, startRef] = useState(null);
  const [end, endRef] = useState(null);

  const [mySelectedDate, setSelectedDate] = useState([]);

  const [isToastOpen, setToastOpen] = useState(false);
  const [toastMessage, setToastMessage] = useState();

  const controls = useMemo(() => (popupEventAllDay ? ['calendar'] : ['calendar', 'time']), [popupEventAllDay]);

  const [myEvents, setMyEvents] = useState([
    {
      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-26T15:00',
      end: '2026-10-26T16:00',
      title: 'Conference',
      description: '',
      allDay: false,
      bufferBefore: 30,
      free: false,
      color: '#ff9900',
    },
    {
      id: 3,
      start: '2026-10-25T18:00',
      end: '2026-10-25T22:00',
      title: 'Site Visit',
      description: '',
      allDay: false,
      bufferBefore: 60,
      free: true,
      color: '#3f51b5',
    },
    {
      id: 4,
      start: '2026-10-27T10:30',
      end: '2026-10-27T11:30',
      title: 'Stakeholder mtg.',
      description: '',
      allDay: false,
      free: false,
      color: '#f44437',
    },
  ]);

  const openPopup = useCallback(() => {
    setDate([new Date(), new Date()]);
    setTitle('New Event');
    setDescription('');
    setAllDay(false);
    setStatus(false);
    setPopupOpen(true);
  }, []);

  const handleClose = useCallback(() => {
    setPopupOpen(false);
  }, []);

  const dateChange = useCallback((args) => {
    setDate(args.value);
  }, []);

  const allDayChange = useCallback((ev) => {
    setAllDay(ev.target.checked);
  }, []);

  const titleChange = useCallback((ev) => {
    setTitle(ev.target.value);
  }, []);

  const descriptionChange = useCallback((ev) => {
    setDescription(ev.target.value);
  }, []);

  const handleCloseToast = useCallback(() => {
    setToastOpen(false);
  }, []);

  return (
    <Page class="mds-full-height">
      <div className="mds-full-height mbsc-flex-col">
        <div className="mbsc-button-group-block">
          <Button onClick={openPopup}>Add new event</Button>
        </div>

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

                handleClose();
                setToastMessage('Event added');
                setToastOpen(true);
              },
              cssClass: 'mbsc-popup-button-primary',
            },
          ]}
          onClose={() => {
            handleClose();
          }}
        >
          <div id="demo-add-event-popup">
            <div className="mbsc-form-group">
              <Input label="Title" value={popupEventTitle} onChange={titleChange} />
              <Input label="Description" value={popupEventDescription} onChange={descriptionChange} />
            </div>
            <div className="mbsc-form-group">
              <Switch label="All-day" checked={popupEventAllDay} onChange={allDayChange} />
              <Input ref={startRef} label="Starts" />
              <Input ref={endRef} label="Ends" />
              <Datepicker
                select="range"
                display="anchored"
                controls={controls}
                touchUi={true}
                startInput={start}
                endInput={end}
                showRangeLabels={false}
                onChange={dateChange}
                value={popupEventDate}
              />
            </div>
            <div className="mbsc-form-group">
              <SegmentedGroup>
                <Segmented value="busy" checked={true}>
                  Show as busy
                </Segmented>
                <Segmented value="free">Show as free</Segmented>
              </SegmentedGroup>
            </div>
          </div>
        </Popup>
        <Eventcalendar class="mbsc-flex-1-1" data={myEvents} selectedDate={mySelectedDate}></Eventcalendar>
        <Toast message={toastMessage} isOpen={isToastOpen} onClose={handleCloseToast} />
      </div>
    </Page>
  );
}

export default App;
```

### TSX

```tsx
import {
  Button,
  Datepicker,
  Eventcalendar,
  Input,
  MbscCalendarEvent,
  MbscDatepickerChangeEvent,
  MbscDatepickerControl,
  MbscDateType,
  Page,
  Popup,
  Segmented,
  SegmentedGroup,
  setOptions,
  Switch,
  Toast,
} from '@mobiscroll/react';
import { ChangeEvent, useCallback, useMemo, useState } from 'react';

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

function App() {
  const [isPopupOpen, setPopupOpen] = useState<boolean>(false);
  const [popupEventAllDay, setAllDay] = useState<boolean>(false);
  const [popupEventTitle, setTitle] = useState<string>('');
  const [popupEventDescription, setDescription] = useState<string>('');
  const [popupEventStatus, setStatus] = useState<boolean>(false);
  const [popupEventDate, setDate] = useState<MbscDateType[]>([]);
  const [start, startRef] = useState<Input | null>(null);
  const [end, endRef] = useState<Input | null>(null);
  const [mySelectedDate, setSelectedDate] = useState<MbscDateType>();

  const [isToastOpen, setToastOpen] = useState(false);
  const [toastMessage, setToastMessage] = useState<string>();

  const controls = useMemo(() => (popupEventAllDay ? ['calendar'] : ['calendar', 'time']) as MbscDatepickerControl[], [popupEventAllDay]);

  const [myEvents, setMyEvents] = useState<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-26T15:00',
      end: '2026-10-26T16:00',
      title: 'Conference',
      description: '',
      allDay: false,
      bufferBefore: 30,
      free: false,
      color: '#ff9900',
    },
    {
      id: 3,
      start: '2026-10-25T18:00',
      end: '2026-10-25T22:00',
      title: 'Site Visit',
      description: '',
      allDay: false,
      bufferBefore: 60,
      free: true,
      color: '#3f51b5',
    },
    {
      id: 4,
      start: '2026-10-27T10:30',
      end: '2026-10-27T11:30',
      title: 'Stakeholder mtg.',
      description: '',
      allDay: false,
      free: false,
      color: '#f44437',
    },
  ]);

  const openPopup = useCallback(() => {
    setDate([new Date(), new Date()]);
    setTitle('New Event');
    setDescription('');
    setAllDay(false);
    setStatus(false);
    setPopupOpen(true);
  }, []);

  const handleClose = useCallback(() => {
    setPopupOpen(false);
  }, []);

  const dateChange = useCallback((args: MbscDatepickerChangeEvent) => {
    setDate(args.value as Array<MbscDateType>);
  }, []);

  const allDayChange = useCallback((ev: ChangeEvent<HTMLInputElement>) => {
    setAllDay(ev.target.checked);
  }, []);

  const titleChange = useCallback((ev: ChangeEvent<HTMLInputElement>) => {
    setTitle(ev.target.value);
  }, []);

  const descriptionChange = useCallback((ev: ChangeEvent<HTMLInputElement>) => {
    setDescription(ev.target.value);
  }, []);

  const handleCloseToast = useCallback(() => {
    setToastOpen(false);
  }, []);

  return (
    <Page class="mds-full-height">
      <div className="mds-full-height mbsc-flex-col">
        <div className="mbsc-button-group-block">
          <Button onClick={openPopup}>Add new event</Button>
        </div>

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

                handleClose();
                setToastMessage('Event added');
                setToastOpen(true);
              },
              cssClass: 'mbsc-popup-button-primary',
            },
          ]}
          onClose={() => {
            handleClose();
          }}
        >
          <div id="demo-add-event-popup">
            <div className="mbsc-form-group">
              <Input label="Title" value={popupEventTitle} onChange={titleChange} />
              <Input label="Description" value={popupEventDescription} onChange={descriptionChange} />
            </div>
            <div className="mbsc-form-group">
              <Switch label="All-day" checked={popupEventAllDay} onChange={allDayChange} />
              <Input ref={startRef} label="Starts" />
              <Input ref={endRef} label="Ends" />
              <Datepicker
                select="range"
                display="anchored"
                controls={controls}
                touchUi={true}
                startInput={start}
                endInput={end}
                showRangeLabels={false}
                onChange={dateChange}
                value={popupEventDate}
              />
            </div>
            <div className="mbsc-form-group">
              <SegmentedGroup>
                <Segmented value="busy" checked={true}>
                  Show as busy
                </Segmented>
                <Segmented value="free">Show as free</Segmented>
              </SegmentedGroup>
            </div>
          </div>
        </Popup>
        <Eventcalendar class="mbsc-flex-1-1" data={myEvents} selectedDate={mySelectedDate}></Eventcalendar>
        <Toast message={toastMessage} isOpen={isToastOpen} onClose={handleCloseToast} />
      </div>
    </Page>
  );
}

export default App;
```

## 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-react.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 react
   ```

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 react --trial`.

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

## Related demos

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