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

# Inside a modal - React Forms demo

React embedded forms in modal or pop-over. Perfect layout for contextual add/edit forms. For React and Next.JS.

- [Live demo](https://demo.mobiscroll.com/react/forms/popup)
- [View React JS code on GitHub](https://github.com/acidb/mobiscroll-demos-react/tree/main/src/demos/form-components/forms/popup)
- [View React TS code on GitHub](https://github.com/acidb/mobiscroll-demos-react-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), [Vue](https://demo.mobiscroll.com/vue/forms/popup.md)

## Description

When working with the [event calendar](https://demo.mobiscroll.com/react/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/react/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

```jsx
const [isOpen, setOpen] = React.useState(false);
const [anchor, setAnchor] = React.useState(null);
const onBtnClick = React.useCallback((args) => {
    setAnchor(args.target);
    setOpen(true);
}, []);

<Button onClick={onBtnClick}>Show modal</Button>
<Popup
    display="anchored"
    buttons={['set', 'cancel']}
>
    <div className="mbsc-form-group">
        <Input label="Title" />
        <Textarea label="Description" />
    </div>
    <div className="mbsc-form-group">
        <Switch label="All-day" />
        <Input label="Starts" />
        <Input label="Ends" />
        <SegmentedGroup>
            <SegmentedItem value="busy" defaultChecked={true}>Show as busy</SegmentedItem>
            <SegmentedItem value="free">Show as free</SegmentedItem>
        </SegmentedGroup>
    </div>
</Popup>
```

## API used in this demo

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

## Code

### JSX

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

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

const popupButtons = ['set', 'cancel'];

const responsivePopup = {
  medium: {
    display: 'anchored',
    width: 400,
    fullScreen: false,
    touchUi: false,
  },
};

function App() {
  const [isOpen, setOpen] = useState(false);
  const [anchor, setAnchor] = useState(null);

  const handleBtnClick = useCallback((args) => {
    setAnchor(args.target);
    setOpen(true);
  }, []);

  const handlePopupClose = useCallback(() => {
    setOpen(false);
  }, []);

  return (
    <Page>
      <Button onClick={handleBtnClick}>Show modal</Button>
      <Popup
        display="anchored"
        contentPadding={false}
        anchor={anchor}
        buttons={popupButtons}
        isOpen={isOpen}
        responsive={responsivePopup}
        onClose={handlePopupClose}
      >
        <div className="mbsc-form-group">
          <Input label="Title" />
          <Textarea label="Description" />
        </div>
        <div className="mbsc-form-group">
          <Switch label="All-day" />
          <Input label="Starts" />
          <Input label="Ends" />
          <SegmentedGroup>
            <Segmented value="busy" defaultChecked={true}>
              Show as busy
            </Segmented>
            <Segmented value="free">Show as free</Segmented>
          </SegmentedGroup>
        </div>
      </Popup>
    </Page>
  );
}

export default App;
```

### TSX

```tsx
import {
  Button,
  Input,
  MbscPopupOptions,
  MbscResponsiveOptions,
  Page,
  Popup,
  Segmented,
  SegmentedGroup,
  setOptions,
  Switch,
  Textarea,
} from '@mobiscroll/react';
import { ChangeEvent, FC, useCallback, useState } from 'react';

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

const popupButtons = ['set', 'cancel'];

const responsivePopup: MbscResponsiveOptions<MbscPopupOptions> = {
  medium: {
    display: 'anchored',
    width: 400,
    fullScreen: false,
    touchUi: false,
  },
};

const App: FC = () => {
  const [anchor, setAnchor] = useState<HTMLElement>();
  const [isOpen, setOpen] = useState<boolean>(false);

  const handleBtnClick = useCallback((args: ChangeEvent<HTMLInputElement>) => {
    setAnchor(args.target);
    setOpen(true);
  }, []);

  const handlePopupClose = useCallback(() => {
    setOpen(false);
  }, []);

  return (
    <Page>
      <Button onClick={handleBtnClick}>Show modal</Button>
      <Popup
        display="anchored"
        contentPadding={false}
        anchor={anchor}
        buttons={popupButtons}
        isOpen={isOpen}
        responsive={responsivePopup}
        onClose={handlePopupClose}
      >
        <div className="mbsc-form-group">
          <Input label="Title" />
          <Textarea label="Description" />
        </div>
        <div className="mbsc-form-group">
          <Switch label="All-day" />
          <Input label="Starts" />
          <Input label="Ends" />
          <SegmentedGroup>
            <Segmented value="busy" defaultChecked={true}>
              Show as busy
            </Segmented>
            <Segmented value="free">Show as free</Segmented>
          </SegmentedGroup>
        </div>
      </Popup>
    </Page>
  );
};
export default App;
```

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

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