---
title: "Javascript Timeline Resource Hover Tooltip Example | Mobiscroll"
component: "Timeline"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/timeline/display-resource-information-on-hover"
---

# Resource Hover Tooltip - JavaScript Timeline demo

Hover over a resource row in the Javascript Timeline to open a tooltip popup with scheduled hours — keeps the timeline view clean. Plain JavaScript API.

- [Live demo](https://demo.mobiscroll.com/javascript/timeline/display-resource-information-on-hover)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/eventcalendar/timeline/display-resource-information-on-hover)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/timeline/display-resource-information-on-hover.md), [Angular](https://demo.mobiscroll.com/angular/timeline/display-resource-information-on-hover.md), [React](https://demo.mobiscroll.com/react/timeline/display-resource-information-on-hover.md), [Vue](https://demo.mobiscroll.com/vue/timeline/display-resource-information-on-hover.md)

## Description

Displaying information in a tooltip can come in handy when space is tight but information matters. When hovering over a resource cell, the [`onResourceHoverIn`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onResourceHoverIn) and [`onResourceHoverOut`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onResourceHoverOut) [lifecycle events](https://demo.mobiscroll.com/javascript/timeline/event-hooks) are triggered, which can be used to show/hide rich tooltips. Information and actions shown here won't clutter the main view, keep the timeline clean while still giving quick access to content that helps.

**Do you want to learn more about customizing the resource header?** [Take a look at this example →](https://demo.mobiscroll.com/javascript/scheduler/custom-resource-header-template)

## What this demo shows

- A desktop resource timeline with hours arranged horizontally and worker resources listed as rows on the left.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move between days, and the Today button returns to the current date.
- **Day view** The day strip shows the selected day, with the current date highlighted. The timeline displays hourly columns from 7 AM to 10 PM.
- **Resources** Each worker appears as a separate resource row with an avatar, name, and profession in the resource column.
- **Resource hover** Hovering over a resource row opens a custom popup with additional worker details.
- **Resource popup** The popup shows the worker avatar, name, hourly rate, scheduled hours for the selected day, estimated earnings, and a Pay action button.
- **Current time** A vertical blue line with a time label marks the current time.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events are shown as colored cards with a left color stripe, a bold title, and the exact start and end time below the title.
- **Date positioning** Events are positioned by their assigned resource and exact date and time range.
- **Event interaction** Events highlight on hover and show drag and resize handles for repositioning or changing duration.
- **Event selection** Clicking an event selects and highlights it.
- **Event creation** New events can be created by double-clicking the timeline or by clicking and dragging across a time range.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through time and resources.

## Best for

- **Workforce management** Showing employee schedules together with role, cost, and daily workload details.
- **Field service scheduling** Reviewing technician assignments while keeping profile details and pay-related actions close to the schedule.
- **Construction and maintenance planning** Coordinating resource-based work across a day timeline with quick access to worker information.
- **Healthcare staffing** Comparing staff assignments by time and resource while showing contextual staff details only when needed.
- **Payroll-aware scheduling** Displaying scheduled hours, hourly rates, estimated earnings, and payment actions alongside planned work.
- **Resource-heavy operations** Keeping the timeline readable while making worker metadata available from the resource column.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-themeVariant) - option
- [`getEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-getEvents) - method
- [`position`](https://mobiscroll.com/docs/javascript/popup/api#method-position) - method
- [`open`](https://mobiscroll.com/docs/javascript/popup/api#method-open) - method
- [`close`](https://mobiscroll.com/docs/javascript/popup/api#method-close) - method
- [`clickToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToResize) - option
- [`eventDelete`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-eventDelete) - option
- [`view`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-view) - option
- [`data`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-resources) - option
- [`renderResource`](https://mobiscroll.com/docs/javascript/eventcalendar/api#renderer-renderResource) - renderer
- [`onResourceHoverIn`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onResourceHoverIn) - event
- [`onResourceHoverOut`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onResourceHoverOut) - event
- [`onPageChange`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onPageChange) - event
- [`display`](https://mobiscroll.com/docs/javascript/popup/api#opt-display) - option
- [`showOverlay`](https://mobiscroll.com/docs/javascript/popup/api#opt-showOverlay) - option
- [`touchUi`](https://mobiscroll.com/docs/javascript/popup/api#opt-touchUi) - option
- [`width`](https://mobiscroll.com/docs/javascript/popup/api#opt-width) - option
- [`onPosition`](https://mobiscroll.com/docs/javascript/popup/api#event-onPosition) - event

## Code

### JS

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

var tooltipElm = document.getElementById('demo-resource-info-popup');
var resourceAvatar = document.getElementById('demo-resource-info-avatar');
var resourceName = document.getElementById('demo-resource-info-name');
var resourceCost = document.getElementById('demo-resource-info-cost');
var resourceDate = document.getElementById('demo-resource-info-date');
var resourceTotal = document.getElementById('demo-resource-info-total');
var payButtonElm = document.getElementById('demo-resource-info-pay');

var hoveredResourceElm = null;
var currentResource = null;
var selectedDate = new Date();
var openTimer;
var closeTimer;

function getTotalHoursForResource(events, resourceId) {
  return events
    .filter(function (e) {
      return e.resource === resourceId;
    })
    .reduce(function (sum, e) {
      var start = new Date(e.start);
      var end = new Date(e.end);
      var hours = (end - start) / (1000 * 60 * 60);
      return sum + hours;
    }, 0);
}

function openTooltip(resource, target) {
  clearTimeout(closeTimer);
  clearTimeout(openTimer);

  // Delay opening the tooltip to avoid flickering
  openTimer = setTimeout(function () {
    var events = calendar.getEvents();
    var totalHours = getTotalHoursForResource(events, resource.id);

    currentResource = resource;
    hoveredResourceElm = target;

    resourceAvatar.src = resource.avatar;
    resourceName.textContent = resource.name;
    resourceCost.textContent = '$' + resource.cost;
    resourceDate.textContent = mobiscroll.formatDate('D DDD MMM YYYY', selectedDate);
    resourceTotal.textContent = totalHours + 'h, $' + totalHours * resource.cost;
    target.classList.add('mds-resource-info-hover');

    tooltip.position();
    tooltip.open();

    openTimer = null;
  }, 100);
}

// Close the tooltip with a delay to allow for hover interactions
function closeTooltip() {
  clearTimeout(openTimer);
  clearTimeout(closeTimer);
  closeTimer = setTimeout(function () {
    tooltip.close();
    closeTimer = null;
  }, 200);
}

var calendar = mobiscroll.eventcalendar('#demo-display-resource-information-on-hover', {
  clickToCreate: true,
  dragToCreate: true,
  dragToMove: true,
  dragToResize: true,
  eventDelete: true
  view: {
    timeline: {
      type: 'day',
      startTime: '07:00',
      endTime: '22:00',
    },
  },
  data: [
    {
      start: '2026-10-22T12:00',
      end: '2026-10-22T15:00',
      title: 'Repoint Brick Facade',
      resource: 'res1',
    },
    {
      start: '2026-10-22T09:00',
      end: '2026-10-22T12:00',
      title: 'Install Custom Wood Trim',
      resource: 'res3',
    },
    {
      start: '2026-10-22T14:00',
      end: '2026-10-22T18:00',
      title: 'Repair Steel Stair Treads',
      resource: 'res4',
    },
    {
      start: '2026-10-22T10:00',
      end: '2026-10-22T13:00',
      title: 'Pour and Finish Driveway Slab',
      resource: 'res6',
    },
    {
      start: '2026-10-22T11:00',
      end: '2026-10-22T16:00',
      title: 'Paint Interior Drywall',
      resource: 'res8',
    },
    {
      start: '2026-10-23T08:00',
      end: '2026-10-23T11:00',
      title: 'Block Wall Construction',
      resource: 'res1',
    },
    {
      start: '2026-10-23T14:00',
      end: '2026-10-23T16:00',
      title: 'Task 2',
      resource: 'Paver Installation',
    },
    {
      start: '2026-10-23T12:00',
      end: '2026-10-23T17:00',
      title: 'Install ceiling fan',
      resource: 'res2',
    },
    {
      start: '2026-10-23T10:00',
      end: '2026-10-23T14:00',
      title: 'Roof Beam Replacement',
      resource: 'res3',
    },
    {
      start: '2026-10-23T07:00',
      end: '2026-10-23T12:00',
      title: 'Custom Metalworks Creation',
      resource: 'res4',
    },
    {
      start: '2026-10-23T14:00',
      end: '2026-10-23T17:00',
      title: 'Pipe Welding',
      resource: 'res4',
    },
    {
      start: '2026-10-10T08:00',
      end: '2026-10-11T20:00',
      title: 'Leak Detection & Repair',
      resource: 'res5',
    },
    {
      start: '2026-10-23T13:00',
      end: '2026-10-23T17:00',
      title: 'Faucet & Sink Fitting',
      resource: 'res5',
    },
    {
      start: '2026-10-23T18:00',
      end: '2026-10-23T20:00',
      title: 'Drainage System Setup',
      resource: 'res5',
    },
    {
      start: '2026-10-23T09:00',
      end: '2026-10-23T13:00',
      title: 'Surface Polishing',
      resource: 'res6',
    },
    {
      start: '2026-10-23T08:00',
      end: '2026-10-23T10:00',
      title: 'Structural Steel Inspections',
      resource: 'res7',
    },
    {
      start: '2026-10-23T13:00',
      end: '2026-10-23T16:00',
      title: 'Metal Structure Assembly',
      resource: 'res7',
    },
    {
      start: '2026-10-23T17:00',
      end: '2026-10-23T19:00',
      title: 'Heavy Steel Beam Placement',
      resource: 'res7',
    },
    {
      start: '2026-10-23T09:00',
      end: '2026-10-23T12:00',
      title: 'Exterior House Painting',
      resource: 'res8',
    },
    {
      start: '2026-10-23T15:00',
      end: '2026-10-23T18:00',
      title: 'Deck Staining & Sealing',
      resource: 'res8',
    },
    {
      start: '2026-10-24T12:00',
      end: '2026-10-24T15:00',
      title: 'Troubleshoot Faulty Breaker',
      resource: 'res2',
    },
    {
      start: '2026-10-24T10:00',
      end: '2026-10-24T13:00',
      title: 'Frame Interior Partitions',
      resource: 'res3',
    },
    {
      start: '2026-10-24T16:00',
      end: '2026-10-24T20:00',
      title: 'Weld Structural Beam Connections',
      resource: 'res4',
    },
    {
      start: '2026-10-24T12:00',
      end: '2026-10-24T16:00',
      title: 'Apply Smooth Trowel Finish to Basement Floor',
      resource: 'res6',
    },
  ],
  resources: [
    {
      id: 'res1',
      name: 'Adam Miller',
      color: '#F39C12',
      profession: 'Mason',
      avatar: 'https://img.mobiscroll.com/demos/m1.png',
      cost: '15',
    },
    {
      id: 'res2',
      name: 'Emily Carter',
      color: '#76e083',
      profession: 'Electrician',
      avatar: 'https://img.mobiscroll.com/demos/f1.png',
      cost: '20',
    },
    {
      id: 'res3',
      name: 'James Brown',
      color: '#b13f49',
      profession: 'Carpenter',
      avatar: 'https://img.mobiscroll.com/demos/m2.png',
      cost: '18',
    },
    {
      id: 'res4',
      name: 'Daniel Wilson',
      color: '#e25dd2',
      profession: 'Welder',
      avatar: 'https://img.mobiscroll.com/demos/m3.png',
      cost: '22',
    },
    {
      id: 'res5',
      name: 'Benjamin Harris',
      color: '#7056ff',
      profession: 'Plumber',
      avatar: 'https://img.mobiscroll.com/demos/m4.png',
      cost: '20',
    },
    {
      id: 'res6',
      name: 'Olivia Anderson',
      color: '#56aaff',
      profession: 'Concrete Finisher',
      avatar: 'https://img.mobiscroll.com/demos/f2.png',
      cost: '15',
    },
    {
      id: 'res7',
      name: 'Emma Thompson',
      color: '#84852f',
      profession: 'Steelworker',
      avatar: 'https://img.mobiscroll.com/demos/f3.png',
      cost: '18',
    },
    {
      id: 'res8',
      name: 'Natalie Roberts',
      color: '#ff6e56',
      profession: 'Painter',
      avatar: 'https://img.mobiscroll.com/demos/f4.png',
      cost: '25',
    },
  ],
  renderResource: function (res) {
    return (
      '<div class="mbsc-flex">' +
      '<img class="mds-resource-info-avatar" src="' +
      res.avatar +
      '"/>' +
      '<div class="mds-resource-info-details">' +
      '<div class="mds-resource-info-title">' +
      res.name +
      '</div>' +
      '<div class="mds-resource-info-profession">' +
      res.profession +
      '</div>' +
      '</div>' +
      '</div>'
    );
  },
  onResourceHoverIn: function (args) {
    openTooltip(args.resource, args.target);
  },
  onResourceHoverOut: function (args) {
    args.target.classList.remove('mds-resource-info-hover');
    closeTooltip();
  },
  onPageChange: function (args) {
    selectedDate = args.firstDay;
  },
});

var tooltip = mobiscroll.popup('#demo-resource-info-popup', {
  display: 'anchored',
  showOverlay: false,
  touchUi: false,
  width: 280,
  onPosition: function (args, inst) {
    var popupElm = args.target.querySelector('.mbsc-popup');
    var rect = hoveredResourceElm.getBoundingClientRect();

    popupElm.style.top = rect.top - 10 + 'px';

    if (inst.s.rtl) {
      popupElm.style.right = window.innerWidth - rect.left + 10 + 'px';
    } else {
      popupElm.style.left = rect.right + 10 + 'px';
    }
    return false; // Prevent default positioning
  },
});

tooltipElm.addEventListener('mouseenter', function () {
  clearTimeout(closeTimer);
});

tooltipElm.addEventListener('mouseleave', function () {
  closeTooltip();
});

payButtonElm.addEventListener('click', function () {
  tooltip.close();
  mobiscroll.toast({
    message: currentResource.name + ' paid',
  });
});
```

### HTML

```html
<div id="demo-resource-info-popup" style="display: none;">
  <div class="mbsc-flex mbsc-align-items-center mds-resource-info-header">
    <img id="demo-resource-info-avatar" class="mds-resource-info-avatar" />
    <div id="demo-resource-info-name" class="mds-resource-info-name mbsc-flex-1-0"></div>
    <button id="demo-resource-info-pay" mbsc-button data-color="success" data-variant="outline" class="mds-resource-info-pay mbsc-button-xs">
      Pay
    </button>
  </div>
  <div class="mds-resource-info-cont">
    <div>
      <span class="mbsc-txt-muted">Hourly rate </span>
      <span id="demo-resource-info-cost" class="mds-resource-info-detail"></span>
    </div>
    <div>
      <span id="demo-resource-info-date" class="mbsc-txt-muted"></span>
      <span id="demo-resource-info-total" class="mds-resource-info-detail"></span>
    </div>
  </div>
</div>
<div id="demo-display-resource-information-on-hover"></div>
```

### CSS

```css
.mds-resource-info-avatar {
  width: 40px;
  height: 40px;
}
.mds-resource-info-details {
  margin: 0 8px;
}
.mds-resource-info-title {
  line-height: 24px;
}
.mds-resource-info-profession {
  font-size: 12px;
  opacity: .5;
  line-height: 18px;
}
.mds-resource-info-hover.mbsc-timeline-resource {
  text-decoration: underline;
}
.mds-resource-info-header {
  height: 35px;
}
.mds-resource-info-name {
  font-size: 18px;
  padding: 16px 10px;
}
.mds-resource-info-pay.mbsc-button {
  margin: 0;
  line-height: 24px;
  padding: 0 10px;
  will-change: opacity;
}
.mds-resource-info-pay .mbsc-button-txt {
  font-size: 12px;
}
.mds-resource-info-cont {
  font-size: 14px;
  line-height: 22px;
  padding-top: 23px;
}
.mbsc-ltr .mds-resource-info-detail {
  float: right;
}
.mbsc-rtl .mds-resource-info-detail {
  float: left;
}
```

## Implementation notes

- Use `timeline: { type: 'day', startTime: '07:00', endTime: '22:00' }` - a single-day view showing 7am-10pm.
- Define 8 worker resources, each with `id`, `name`, `color`, `profession`, `avatar` (image URL), and `cost` ($/hour).
- Add ~24 task events across yesterday/today/tomorrow with `dyndatetime` offsets and hourly start/end times.
- **Custom resource row** (`renderResource` / `resourceTemplate` / `resource` slot): renders the worker's avatar image alongside their name and profession.
- **Hover tooltip** - implemented with debounced open/close timers to avoid flickering and to allow the cursor to travel from the resource row into the popup without dismissal:
  - `onResourceHoverIn`: cancel both timers, start a 100ms open timer. When it fires: compute total scheduled hours for the resource (see below), add a CSS highlight class (`mds-resource-info-hover`) to `args.target`, populate tooltip state (avatar, name, hourly rate, formatted date, total hours + total cost), call `popupRef.position()`, then open the popup.
  - `onResourceHoverOut`: remove the highlight class from `args.target`, cancel the open timer, start a 200ms close timer.
  - On the popup's wrapping element: `onMouseEnter` cancels the close timer (keeps popup open); `onMouseLeave` starts the close timer again.
- **Popup**: `display: 'anchored'`, `showOverlay: false`, `touchUi: false`, `width: 280`. Content: avatar + name + a "Pay" button (outline/success) in the header row; below that, hourly rate and a line showing the current day's total hours and total cost (`hours * rate`).
- **Custom popup positioning** (`onPosition`): read the hovered resource element's `getBoundingClientRect()`, set the popup 10px to the right of the element (`rect.right + 10`) and aligned to its top (`rect.top - 10`). For RTL, use `window.innerWidth - rect.left + 10` for the right offset. Return `false` to suppress Mobiscroll's default positioning.
- **Total hours**: use `calRef.getEvents()`, filter by resource id, sum `(end - start) / (1000 * 60 * 60)` across all events visible on the current day.
- **Date display**: track the visible date via `onPageChange` (`args.firstDay`); format it with `formatDate('D DDD MMM YYYY', date)` for the tooltip.
- **"Pay" button**: closes the tooltip and shows a `Toast` with `"<name> paid"`.

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

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

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

## Related demos

- Previous: [Resource Properties](https://demo.mobiscroll.com/javascript/timeline/resource-data-structure.md) - Define resource properties on the Javascript Timeline — set up nested groups, fixed rows, and per-resource drag, resize, and overlap controls.
