---
title: "React Event calendar Custom Event Popover Example | Mobiscroll"
component: "Event calendar"
framework: "React"
library_version: "6.2.0"
url: "https://demo.mobiscroll.com/react/eventcalendar/customize-event-popover"
---

# Custom Event Popover - React Event calendar demo

Customize how events appear in the day popover of a React event calendar — use full custom layouts or add fields like assignee, location, and participants. For React and Next.js.

- [Live demo](https://demo.mobiscroll.com/react/eventcalendar/customize-event-popover)
- [View React JS code on GitHub](https://github.com/acidb/mobiscroll-demos-react/tree/main/src/demos/eventcalendar/calendar-view/customize-event-popover)
- [View React TS code on GitHub](https://github.com/acidb/mobiscroll-demos-react-ts/tree/main/src/demos/eventcalendar/calendar-view/customize-event-popover)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/eventcalendar/customize-event-popover.md), [jQuery](https://demo.mobiscroll.com/jquery/eventcalendar/customize-event-popover.md), [Angular](https://demo.mobiscroll.com/angular/eventcalendar/customize-event-popover.md), [Vue](https://demo.mobiscroll.com/vue/eventcalendar/customize-event-popover.md)

## Description

The events listed in the popover can be customized in two ways:

- **Full event customization** *(like in this example)* - The calendar handles the rendering of events in the correct order. Styling the content, colors and everything else is your responsibility.
- **Content customization** - The calendar prints the `start` and `end` times, `allDay` and sets the appropriate `color`. Content like title and other fields can be shown.

You can provide styling to the `title` field and any other custom fields like `description`, `location`, `participants` ...

Pass a rendering function to the [`renderPopoverEventContent` option](https://mobiscroll.com/docs/react/eventcalendar/api#renderer-renderPopoverEventContent). All original event fields along with computed fields like `isMultiDay`, `lastDay` are passed to the function. For a fully custom event rendering use the [`renderPopoverEvent` option](https://mobiscroll.com/docs/react/eventcalendar/api#renderer-renderPopoverEvent).

If you add custom markup you will want to add styling too. Use the `popoverClass` under the `view` option to tell the calendar what CSS class it should append to the popover container so that you can write specific CSS rules.

## What this demo shows

- A mobile-style month event calendar with fully customized events shown in the popover.
- **Month grid** Days with scheduled events show a small marker below the day number.
- **Day hover state** Hovering over a day cell highlights the day number with a gray background.
- **Day selection** Clicking a day selects it and highlights the day number with a blue background.
- **Popover trigger** Clicking a day with an event marker opens a popover below the day cell.
- **Popover content** The popover lists the events scheduled for the selected day.
- **Custom event layout** Each customized event includes a colored leading line, event title, assignee image, assignee name, and time information.
- **All-day events** All-day events display an `All-day` label instead of a time range.
- **Timed events** Time-specific events display the start and end time.
- **Event action** Each event includes a blue `Add participant` button that highlights on hover and can be wired to a custom action.
- **Calendar navigation** The calendar supports horizontal drag navigation for moving between months.
- **Header controls** The header shows the current month and year on the left side, while the right side includes blue previous and next navigation arrows, and a `Today` button for returning to the current date.

## Best for

- **Assigned work and people-based scheduling** Displaying assignees, avatars, and event ownership directly in the popover list.
- **Actionable event lists** Adding buttons or other controls to day-level event previews so users can trigger follow-up actions from the popover.
- **Compact month browsing** Letting users scan a month quickly, spot days with events, and open a lightweight detail view only when needed.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-themeVariant) - option
- [`labels`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-labels) - option
- [`clickToCreate`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToResize) - option
- [`eventDelete`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-eventDelete) - option
- [`renderPopoverEventContent`](https://mobiscroll.com/docs/react/eventcalendar/api#renderer-renderPopoverEventContent) - renderer
- [`data`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-data) - option
- [`view`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-view) - option
- [`onClose`](https://mobiscroll.com/docs/react/notifications/toast#event-onClose) - event

## Code

### JSX

```jsx
import { Button, Eventcalendar, getJson, setOptions, Toast } from '@mobiscroll/react';
import { useCallback, useEffect, useMemo, useState } from 'react';

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

function App() {
  const [myEvents, setEvents] = useState([]);
  const [isToastOpen, setToastOpen] = useState(false);
  const [toastText, setToastText] = useState();

  const myView = useMemo(
    () => ({
      calendar: {
        labels: false,
        popover: true,
        popoverClass: 'custom-event-popover',
      },
    }),
    [],
  );

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

  const getParticipant = useCallback((id) => {
    switch (id) {
      case 1:
        return {
          img: 'https://img.mobiscroll.com/demos/m1.png',
          name: 'Barry L.',
        };
      case 2:
        return {
          img: 'https://img.mobiscroll.com/demos/f1.png',
          name: 'Hortense T.',
        };
      case 3:
        return {
          img: 'https://img.mobiscroll.com/demos/m2.png',
          name: 'Carl H.',
        };
    }
  }, []);

  const add = useCallback(
    (ev, data) => {
      ev.stopPropagation();
      setToastText(getParticipant(data.participant).name + "'s event clicked");
      setToastOpen(true);
    },
    [getParticipant],
  );

  const customEventContent = useCallback(
    (data) => (
      <>
        <div>{data.title}</div>
        <div className="md-custom-event-cont">
          <img className="md-custom-event-img" src={getParticipant(data.original.participant).img} />
          <div className="mbsc-custom-event-name">{getParticipant(data.original.participant).name}</div>
          <Button className="md-custom-event-btn" color="primary" variant="outline" onClick={(domEvent) => add(domEvent, data.original)}>
            Add participant
          </Button>
        </div>
      </>
    ),
    [add, getParticipant],
  );

  useEffect(() => {
    getJson(
      'https://trial.mobiscroll.com/custom-events/',
      (events) => {
        setEvents(events);
      },
      'jsonp',
    );
  }, []);

  return (
    <>
      <Eventcalendar
        clickToCreate={true}
        dragToCreate={true}
        dragToMove={true}
        dragToResize={true}
        eventDelete={true}
        renderPopoverEventContent={customEventContent}
        data={myEvents}
        view={myView}
      />
      <Toast message={toastText} isOpen={isToastOpen} onClose={handleToastClose} />
    </>
  );
}

export default App;
```

### TSX

```tsx
import {
  Button,
  Eventcalendar,
  getJson,
  MbscCalendarEvent,
  MbscCalendarEventData,
  MbscEventcalendarView,
  setOptions,
  Toast,
} from '@mobiscroll/react';
import { ChangeEvent, FC, useCallback, useEffect, useMemo, useState } from 'react';

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

const App: FC = () => {
  const [myEvents, setEvents] = useState<MbscCalendarEvent[]>([]);
  const [isToastOpen, setToastOpen] = useState<boolean>(false);
  const [toastText, setToastText] = useState<string>();

  const myView = useMemo<MbscEventcalendarView>(
    () => ({
      calendar: {
        labels: false,
        popover: true,
        popoverClass: 'custom-event-popover',
      },
    }),
    [],
  );

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

  const getParticipant = (id: number) => {
    switch (id) {
      case 1:
        return {
          img: 'https://img.mobiscroll.com/demos/m1.png',
          name: 'Barry L.',
        };
      case 2:
        return {
          img: 'https://img.mobiscroll.com/demos/f1.png',
          name: 'Hortense T.',
        };
      case 3:
        return {
          img: 'https://img.mobiscroll.com/demos/m2.png',
          name: 'Carl H.',
        };
      default:
        return {
          img: '',
          name: '',
        };
    }
  };

  const add = useCallback((ev: ChangeEvent<HTMLInputElement>, data: MbscCalendarEvent) => {
    ev.stopPropagation();
    setToastText(getParticipant(data.participant).name + "'s event clicked");
    setToastOpen(true);
  }, []);

  const customEventContent = useCallback(
    (data: MbscCalendarEventData) => {
      const original = data.original!;
      return (
        <>
          <div>{data.title}</div>
          <div className="md-custom-event-cont">
            <img className="md-custom-event-img" src={getParticipant(original.participant).img} />
            <div className="mbsc-custom-event-name">{getParticipant(original.participant).name}</div>
            <Button
              className="md-custom-event-btn"
              color="primary"
              variant="outline"
              onClick={(domEvent: ChangeEvent<HTMLInputElement>) => add(domEvent, original)}
            >
              Add participant
            </Button>
          </div>
        </>
      );
    },
    [add],
  );

  useEffect(() => {
    getJson(
      'https://trial.mobiscroll.com/custom-events/',
      (events: MbscCalendarEvent[]) => {
        setEvents(events);
      },
      'jsonp',
    );
  }, []);

  return (
    <div>
      <Eventcalendar
        clickToCreate={true}
        dragToCreate={true}
        dragToMove={true}
        dragToResize={true}
        eventDelete={true}
        renderPopoverEventContent={customEventContent}
        data={myEvents}
        view={myView}
      />
      <Toast message={toastText} isOpen={isToastOpen} onClose={handleToastClose} />
    </div>
  );
};
export default App;
```

### CSS

```css
.md-custom-event-img {
  width: 30px;
  height: 30px;
}

.mbsc-custom-event-name {
  padding: 0 10px;
}

.md-custom-event-cont {
  display: flex;
  align-items: center;
  padding-top: 10px;
  font-size: 13px;
}

.md-custom-event-btn.mbsc-button {
  position: absolute;
  right: 10px;
  bottom: 8px;
  line-height: 20px;
  padding: 0px 6px;
}

.custom-event-popover.mbsc-material .mbsc-popover-list .mbsc-event {
  padding: 10px 14px;
}

.custom-event-popover.mbsc-ios .mbsc-popover-list {
  width: 340px;
}

.custom-event-popover.mbsc-material .mbsc-popover-list {
  width: 320px;
}

.custom-event-popover.mbsc-windows .mbsc-popover-list {
  width: 340px;
}
```

## Implementation notes

- Set `view: { calendar: { labels: false, popover: true, popoverClass: 'custom-event-popover' } }`: `labels: false` suppresses inline labels so only a dot marker appears; `popover: true` opens the event list on day click; `popoverClass` adds a custom CSS class to the popover container for targeted styling.
- Use `renderPopoverEventContent` (Angular: `popoverEventContentTemplate`, Vue: `popoverEventContent` slot) to customize the content of each event row in the popover while the calendar handles event ordering and the outer popover frame. The render function receives `data` with `data.title` and `data.original` for any custom event fields - this demo uses `data.original.participant` to look up an assignee name and avatar image. For full control over the outer event wrapper, use `renderPopoverEvent` (Angular: `popoverEventTemplate`, Vue: `popoverEvent` slot) instead.
- Add a `Button` inside the custom content with `color="primary"` and `variant="outline"`. Call `ev.stopPropagation()` in its click handler to prevent the calendar's `onEventClick` from firing, then show a `Toast` with the participant's name.
- Load events from a remote endpoint using `getJson` and assign them to `data`; for the imperative API, call `inst.setEvents(events)` in the callback.

## 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: [Custom Label Styling](https://demo.mobiscroll.com/react/eventcalendar/customize-label-look-and-feel.md) - Fully customize event labels in the React event calendar — set colors, show timed-event dots, and include custom fields beyond the event title.
- Next: [Custom Header](https://demo.mobiscroll.com/react/eventcalendar/customizing-header.md) - Customize the React event calendar header — rearrange navigation controls, toggle calendar/scheduler views or add any custom action.
