---
title: "JQuery Timeline Custom Cell Content Example | Mobiscroll"
component: "Timeline"
framework: "jQuery"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/jquery/timeline/dynamic-cell-content-template"
---

# Custom Cell Content - jQuery Timeline demo

Add workload badges, status icons, and a hover quick-add button to each JQuery Timeline cell — and cap events per cell.

- [Live demo](https://demo.mobiscroll.com/jquery/timeline/dynamic-cell-content-template)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-jquery/tree/main/src/demos/eventcalendar/timeline/dynamic-cell-content-template)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/dynamic-cell-content-template.md), [Angular](https://demo.mobiscroll.com/angular/timeline/dynamic-cell-content-template.md), [React](https://demo.mobiscroll.com/react/timeline/dynamic-cell-content-template.md), [Vue](https://demo.mobiscroll.com/vue/timeline/dynamic-cell-content-template.md)

## Description

Dynamically customize the cell content of the timeline by showing event-related icons, visual indicators, and a quick add button directly in each cell.

This is achieved using the [`renderCell`](https://mobiscroll.com/docs/jquery/eventcalendar/timeline#renderer-renderCell) function, where event data in each cell is used to display icons based on the event, a badge showing total event hours, and a button to quickly add new events. The add event icon is dynamically added during [`onCellHoverIn`](https://mobiscroll.com/docs/jquery/eventcalendar/timeline#event-onCellHoverIn). An event cap per cell is implemented by reading the event count from [`onCellHoverIn`](https://mobiscroll.com/docs/jquery/eventcalendar/timeline#event-onCellHoverIn) args and enforcing it in [`onEventCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/timeline#event-onEventCreate), blocking event creation by returning `false`. This approach helps visualize workload per day and enables quick actions, making scheduling more efficient and user-friendly.

In this demo, cells represent a day. Depending on the resolution, they can also stand for a week, month, or more, while remaining fully customizable. See this [configuration demo](https://demo.mobiscroll.com/jquery/timeline/multiple-days-weeks-months-quarters-years-variable-resolution) to try out different timeline resolution settings.

## What this demo shows

- A desktop monthly timeline where days are arranged horizontally and resources are listed as rows on the left.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move the visible timeline range, and the Today button returns to the current date.
- **Month view** The timeline header shows the days of the selected month, with the current date highlighted.
- **Resources** Multiple resources are displayed as separate timeline rows.
- **Custom cell content** Each resource-day cell shows scheduled hours against available working hours, such as `8h`.
- **Workload indicators** Color-coded badges show resource utilization at a glance, including fully utilized, partially utilized, and overloaded or underutilized states based on the configured rules.
- **Task overview** Individual tasks remain visible beneath the workload summary, so each cell shows both daily capacity and scheduled work.
- **Dynamic summaries** Workload totals reflect the current events in the cell when event data changes.
- **Status icons** Custom icons can represent task metadata, priorities, activity types, or other event categories.
- **Event labels** Events are displayed as blue labels with the event title and duration.
- **Event creation** A `+` button appears in the upper-right corner of a cell on hover and can be used to add a new event.
- **Date positioning** Events are placed by their assigned resource and date.
- **Event interaction** Events highlight on hover.
- **Event selection** Clicking an event selects and highlights it.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through dates and resources.

## Best for

- **Workforce scheduling** Planning daily work across multiple people, teams, or resource groups.
- **Project planning** Comparing assigned work against available capacity by resource and day.
- **Field service scheduling** Reviewing technician or crew workload across a monthly timeline.
- **Manufacturing planning** Balancing daily tasks across machines, stations, or production resources.
- **Resource management** Spotting overbooked, underused, or partially allocated resources in a timeline layout.
- **Capacity planning** Showing workload totals and task details together without leaving the calendar view.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-themeVariant) - option
- [`clickToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToResize) - option
- [`extendDefaultEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-extendDefaultEvent) - option
- [`cssClass`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-cssClass) - option
- [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) - option
- [`renderCell`](https://mobiscroll.com/docs/jquery/eventcalendar/api#renderer-renderCell) - renderer
- [`renderTimelineEventContent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#renderer-renderTimelineEventContent) - renderer
- [`onCellHoverIn`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onCellHoverIn) - event
- [`onEventCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreate) - event
- [`data`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-resources) - option
- [`addEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-addEvent) - method

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

var myEvents = [
  {
    id: 1,
    resource: 1,
    title: 'Review',
    start: '2026-11-01T00:00',
    end: '2026-11-01T02:00',
  },
  {
    id: 2,
    resource: 1,
    title: 'Demo',
    start: '2026-11-01T00:00',
    end: '2026-11-01T02:00',
  },
  {
    id: 3,
    resource: 1,
    title: 'Kickoff',
    start: '2026-11-01T00:00',
    end: '2026-11-01T02:00',
  },
  {
    id: 4,
    resource: 4,
    title: 'Strategy',
    start: '2026-11-01T00:00',
    end: '2026-11-01T02:00',
  },
  {
    id: 5,
    resource: 4,
    title: 'Collab',
    start: '2026-11-01T00:00',
    end: '2026-11-01T02:00',
  },
  // Showing partial data. Download full source.
];

var myResources = [
  { id: 1, name: 'Resource A' },
  { id: 2, name: 'Resource B' },
  { id: 3, name: 'Resource C' },
  { id: 4, name: 'Resource D' },
];

var hoveredDate;
var hoveredResource;
var hoveredCellEventCount;

var iconMap = {
  Review: 'calendar',
  Demo: 'play',
  Kickoff: 'flag',
  Strategy: 'map',
  Collab: 'bubbles',
  Update: 'upload',
  Discussion: 'bubble',
  Planning: 'pencil',
  Retrospect: 'history',
  Onboard: 'user4',
};
var titles = Object.keys(iconMap);

$(function () {
  var calendar = $('#demo-cell-content')
    .mobiscroll()
    .eventcalendar({
      clickToCreate: false,
      dragToCreate: false,
      dragToMove: false,
      dragToResize: false,
      extendDefaultEvent: function (args) {
        return {
          title: titles[Math.floor(Math.random() * titles.length)],
          end: new Date(args.start.getTime() + 2 * 3600000),
        };
      },
      cssClass: 'mds-timeline-cell-content',
      view: {
        timeline: {
          endDay: 5,
          eventDisplay: 'fill',
          type: 'month',
          resolutionHorizontal: 'day',
          startDay: 1,
        },
      },
      renderCell: function (args) {
        var events = args.events;
        var hours = Math.round(
          events.reduce(function (s, ev) {
            return s + (new Date(ev.end) - new Date(ev.start)) / 36e5;
          }, 0),
        );
        var classMap = { 2: 'light', 4: 'medium', 6: 'semi', 8: 'full' };
        var colorClass = 'mds-timeline-cell-content-badge-' + (classMap[hours] || 'default');

        var iconHtml = '';
        var addedIcons = new Set();

        for (var i = 0; i < events.length; i++) {
          var ev = events[i];
          var iconName = iconMap[ev.title];
          if (iconName && !addedIcons.has(ev.title)) {
            iconHtml += '<i class="mbsc-font-icon mbsc-icon-' + iconName + ' mds-timeline-cell-icon" title="' + ev.title + '"></i>';
            addedIcons.add(ev.title);
          }
        }

        return (
          '<div class="mds-timeline-cell-content-badge ' +
          colorClass +
          '">' +
          hours +
          'h / 8h</div>' +
          '<button class="mds-timeline-cell-content-add"><span>+</span></button>' +
          '<div class="mds-timeline-cell-icons">' +
          iconHtml +
          '</div>'
        );
      },
      renderTimelineEventContent: function (event) {
        var hours = Math.round((event.endDate - event.startDate) / 36e5);
        return '<div>' + event.title + ' - ' + hours + 'h</div>';
      },
      onCellHoverIn: function (args) {
        hoveredDate = args.date;
        hoveredResource = args.resource.id;
        hoveredCellEventCount = args.events.length;
      },
      onEventCreate: function () {
        if (hoveredCellEventCount >= 4) {
          mobiscroll.toast({
            message: 'Task limit reached',
          });
          return false;
        }
      },
      data: myEvents,
      resources: myResources,
    })
    .mobiscroll('getInst');

  $(document).on('click', '.mds-timeline-cell-content-add', function () {
    if (!hoveredDate || !hoveredResource) {
      return;
    }

    if (hoveredCellEventCount >= 4) {
      mobiscroll.toast({
        message: 'Task limit reached',
      });
      return;
    }

    calendar.addEvent({
      start: hoveredDate,
      end: new Date(hoveredDate.getTime() + 2 * 3600000),
      resource: hoveredResource,
      title: titles[Math.floor(Math.random() * titles.length)],
    });

    hoveredCellEventCount++;
  });
});
```

### HTML

```html
<div id="demo-cell-content"></div>
```

### CSS

```css
.mds-timeline-cell-content .mbsc-timeline-day-fri::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  border-right: 1px solid var(--mbsc-eventcalendar-border-color);
}

.mds-timeline-cell-content .mbsc-timeline-day-fri.mbsc-ltr::after {
  left: 100%;
}

.mds-timeline-cell-content .mbsc-timeline-day-fri.mbsc-rtl::after {
  right: 100%;
}

.mds-timeline-cell-content .mbsc-timeline-events {
  top: 25px;
}

.mds-timeline-cell-content .mbsc-timeline-row-gutter {
  height: 55px;
}

.mds-timeline-cell-content .mbsc-timeline-column {
  width: 110px;
}

.mds-timeline-cell-content-badge {
  position: relative;
  top: 6px;
  left: 4px;
  display: inline-block;
  padding: 1px 4px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 12px;
  max-width: 80px;
  color: black;
  background: #f9f9f9;
  overflow: hidden;
  z-index: 0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

.mds-timeline-cell-content-badge::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  transform: skewX(-15deg);
  z-index: -1;
}

.mds-timeline-cell-content-badge-light::before {
  width: 25%;
  background: #ff9c9c
  }
  
.mds-timeline-cell-content-badge-medium::before {
  width: 50%;
  background: #ffcf9f
}
    
.mds-timeline-cell-content-badge-semi::before {
  width: 75%;
  background: #fff4a3 
}
      
.mds-timeline-cell-content-badge-full::before {
  width: 100%;
  background: #a3e4a1 
}

.mds-timeline-cell-content-add {
  opacity: 0;
  position: absolute;
  top: 6px;
  width: 17px;
  height: 17px;
  line-height: 13px;
  padding: 0;
  padding-bottom: 4px;
  color: #fff;
  border: none;
  border-radius: 50%;
  font-size: 22px;
  cursor: pointer;
  background: linear-gradient(135deg,rgb(73, 73, 73),rgb(22, 21, 21));
  transition: transform 0.2s ease;
}

.mbsc-timeline-column.mbsc-ltr .mds-timeline-cell-content-add {
  right: 4px;
}

.mbsc-timeline-column.mbsc-rtl .mds-timeline-cell-content-add {
  left: 4px;
}

.mbsc-timeline-column:hover .mds-timeline-cell-content-add {
  opacity: 1;
  pointer-events: auto;
}

.mds-timeline-cell-content-add:hover {
  outline: 3px solid rgba(140, 140, 140, 0.5);
}

.mds-timeline-cell-icons {
  position: absolute;
  inset: auto auto 4px auto;
}

.mds-timeline-cell-icon {
  text-align: center;
  padding: 2px 4px;
  margin: 0 3px;
  line-height: 17px !important;
  color: #000;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 5px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
  font-size: 13px;
}
```

## Implementation notes

- Use `timeline: { type: 'month', resolutionHorizontal: 'day', startDay: 1, endDay: 5, eventDisplay: 'fill' }` - a monthly timeline with one column per day, Mon-Fri only, events listed as fills rather than positioned by time.
- Define 4 plain resources (Resource A-D) with only `id` and `name` - no `color` needed. Events have no `color` either; the cell badge provides the workload indicator instead.
- Build an `iconMap` that maps event title strings to Mobiscroll icon names (e.g. `Review → 'calendar'`, `Demo → 'play'`, `Kickoff → 'flag'`). Use the keys of this map as the pool of valid event titles.
- Use `renderCell` (Angular: `cellTemplate`, Vue: `#cell`) to inject content into each timeline cell. The render function receives a `cell` object with `cell.events` (the events on that cell), `cell.date`, and `cell.resource`. From `cell.events`, compute the total scheduled hours by summing each event's duration, and render: a workload badge showing `{hours}h / 8h`, a "+" add button, and a row of deduplicated event-type icons (one icon per distinct title using `mbsc-icon-{iconName}`).
- Use `renderTimelineEventContent` (Angular: `timelineEventContentTemplate`, Vue: `#timelineEventContent`) to render a compact event label showing the event title and its duration in hours, calculated from `event.endDate` and `event.startDate`.
- In the "+" button's click handler, read `cell.events.length`. If it is 4 or more, show a `Toast` with "Task limit reached" and return early. Otherwise, add a new event to the events array with `start: cell.date`, `end: 2 hours later`, `resource: cell.resource.id`, and a random title from the titles pool. In Angular, call `stopPropagation()` on the click event to prevent the calendar from handling it.
- Use `extendDefaultEvent` returning a random title from the titles pool and an `end` 2 hours after `args.start`, so the same defaults apply to any events created via other means.
- Disable all built-in interaction: set `clickToCreate`, `dragToCreate`, `dragToMove`, and `dragToResize` all to `false`.

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

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

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

## Related demos

- Previous: [Event Appearance & Time Buffers](https://demo.mobiscroll.com/jquery/timeline/timeline-custom-event-rendering.md) - Customize event layouts on a JQuery Timeline with icons, labels, and colors — visualize before/after buffers for travel, prep, or inspection workflows.
- Next: [Header and Footer Template](https://demo.mobiscroll.com/jquery/timeline/hour-day-week-month-quarter-year-header-footer-template.md) - Customize time-scale headers and add occupancy footers to a JQuery Timeline — format cells from hour to year and display per-slot utilization.
