---
title: "Vue Timeline Cell Hover Highlight Example | Mobiscroll"
component: "Timeline"
framework: "Vue"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/vue/timeline/dynamic-resource-column-highlight-on-cell-hover"
---

# Cell Hover Highlight - Vue Timeline demo

Add row and column hover highlighting to a Vue resource timeline — highlight the active resource row and date column on hover. For Vue and Nuxt.

- [Live demo](https://demo.mobiscroll.com/vue/timeline/dynamic-resource-column-highlight-on-cell-hover)
- [View SFC JS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue/tree/main/src/demos/eventcalendar/timeline/dynamic-resource-column-highlight-on-cell-hover)
- [View SFC TS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue-ts/tree/main/src/demos/eventcalendar/timeline/dynamic-resource-column-highlight-on-cell-hover)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/dynamic-resource-column-highlight-on-cell-hover.md), [jQuery](https://demo.mobiscroll.com/jquery/timeline/dynamic-resource-column-highlight-on-cell-hover.md), [Angular](https://demo.mobiscroll.com/angular/timeline/dynamic-resource-column-highlight-on-cell-hover.md), [React](https://demo.mobiscroll.com/react/timeline/dynamic-resource-column-highlight-on-cell-hover.md)

## Description

Highlight the resource row and date column on cell hover to improve usability by clearly showing where the user is interacting.

This is achieved using the `onCellHoverIn` and `onCellHoverOut` lifecycle events. These track the hovered cell and update the resources with a custom `cssClass`, which highlights the resource row. A popup is also shown on hover, displaying relevant information about the cell like the date and resource name.

The column highlight is applied using the `renderCell`, `renderSidebar`, `renderTimelineDay`, and `renderDayFooter` callbacks, where conditional markup is returned to highlight the vertical column.

This makes it easy to implement custom hover interactions that match your design and UX goals.

## What this demo shows

- A desktop monthly timeline with days arranged horizontally and resources listed as rows.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move between months, and the Today button returns to the current date.
- **Month view** The timeline displays the days of the selected month as horizontal date columns.
- **Footer** The bottom strip repeats the days of the selected month.
- **Resources** Multiple resources are shown as separate timeline rows on the left.
- **Sidebar** Resource names are also rendered in a right-side sidebar.
- **Cell hover** Hovering a timeline cell highlights both the resource row and the date column, making the active cell context clear.
- **Hover popup** A popup appears on cell hover with contextual information, including the resource name and date.
- **Column highlight** The highlighted date column is applied across the timeline body, day header, footer, and sidebar rendering areas.
- **Event cards** Events appear as colored cards with a colored stripe, bold event title, and exact start and end time.
- **Date positioning** Events are positioned by their assigned resource and date 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 dates and resources.

## Best for

- **Resource timelines** Applications that need to show many resources against a shared monthly timeline.
- **Context-heavy scheduling** Scheduling interfaces where users need clear row and column feedback before creating, moving, or resizing events.
- **Operational dashboards** Planning views that benefit from contextual hover details without opening a full editor.
- **Asset management** Interfaces for tracking equipment, rooms, vehicles, or other assignable resources over time.
- **Workforce scheduling** Staff planning views where resource names, dates, and scheduled work need to stay easy to follow.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-themeVariant) - option
- [`cssClass`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-cssClass) - option
- [`view`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-view) - option
- [`data`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-resources) - option
- [`cell-hover-in`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onCellHoverIn) - event
- [`cell-hover-out`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onCellHoverOut) - event
- [`anchor`](https://mobiscroll.com/docs/vue/popup/api#opt-anchor) - option
- [`display`](https://mobiscroll.com/docs/vue/popup/api#opt-display) - option
- [`focusOnClose`](https://mobiscroll.com/docs/vue/popup/api#opt-focusOnClose) - option
- [`isOpen`](https://mobiscroll.com/docs/vue/popup/api#opt-isOpen) - option
- [`scrollLock`](https://mobiscroll.com/docs/vue/popup/api#opt-scrollLock) - option
- [`showOverlay`](https://mobiscroll.com/docs/vue/popup/api#opt-showOverlay) - option

## Code

### SFC JS

```vue
<script setup>
import { formatDate, MbscEventcalendar, MbscPopup, setOptions } from '@mobiscroll/vue'
import { ref } from 'vue'

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

const anchor = ref(null)
const hoverDate = ref(null)
const hoverResource = ref(null)
const isPopupOpen = ref(false)

const myView = {
  timeline: {
    type: 'month',
    resolutionHorizontal: 'day'
  }
}

const myEvents = ref([
  { start: '2026-10-02T00:00', end: '2026-10-05T00:00', title: 'Event 1', resource: 1 },
  { start: '2026-10-10T09:00', end: '2026-10-15T15:00', title: 'Event 2', resource: 3 },
  { start: '2026-10-12T00:00', end: '2026-10-14T00:00', title: 'Event 3', resource: 4 },
  { start: '2026-10-15T07:00', end: '2026-10-20T12:00', title: 'Event 4', resource: 5 },
  { start: '2026-10-03T00:00', end: '2026-10-10T00:00', title: 'Event 5', resource: 6 },
  { start: '2026-10-10T08:00', end: '2026-10-11T20:00', title: 'Event 6', resource: 7 },
  { start: '2026-10-22T00:00', end: '2026-10-28T00:00', title: 'Event 7', resource: 7 },
  { start: '2026-10-08T00:00', end: '2026-10-13T00:00', title: 'Event 8', resource: 15 },
  { start: '2026-10-25T00:00', end: '2026-10-27T00:00', title: 'Event 9', resource: 10 },
  { start: '2026-10-20T00:00', end: '2026-10-23T00:00', title: 'Event 10', resource: 12 }
])

const myResources = ref([
  { id: 1, name: 'Resource A', color: '#e20000', cssClass: '' },
  { id: 2, name: 'Resource B', color: '#76e083', cssClass: '' },
  { id: 3, name: 'Resource C', color: '#4981d6', cssClass: '' },
  { id: 4, name: 'Resource D', color: '#e25dd2', cssClass: '' },
  { id: 5, name: 'Resource E', color: '#1dab2f', cssClass: '' },
  { id: 6, name: 'Resource F', color: '#d6d145', cssClass: '' },
  { id: 7, name: 'Resource G', color: '#34c8e0', cssClass: '' },
  { id: 8, name: 'Resource H', color: '#9dde46', cssClass: '' },
  { id: 9, name: 'Resource I', color: '#166f6f', cssClass: '' },
  { id: 10, name: 'Resource J', color: '#f7961e', cssClass: '' },
  { id: 11, name: 'Resource K', color: '#34c8e0', cssClass: '' },
  { id: 12, name: 'Resource L', color: '#af0000', cssClass: '' },
  { id: 13, name: 'Resource M', color: '#446f1c', cssClass: '' },
  { id: 14, name: 'Resource N', color: '#073138', cssClass: '' },
  { id: 15, name: 'Resource O', color: '#4caf00', cssClass: '' }
])

function handleCellHoverIn(args) {
  const resId = args.resource.id
  myResources.value = myResources.value.map((r) => ({
    ...r,
    cssClass: r.id === resId ? 'mds-highlight-row-hover' : ''
  }))

  hoverDate.value = args.date
  hoverResource.value = myResources.value.find((r) => r.id === resId) || null
  anchor.value = args.domEvent.target || null
  isPopupOpen.value = true
}

function handleCellHoverOut() {
  hoverDate.value = null
  hoverResource.value = null
  myResources.value = myResources.value.map((r) => ({ ...r, cssClass: '' }))
  isPopupOpen.value = false
}
</script>

<template>
  <MbscEventcalendar
    cssClass="mds-highlight-hover"
    :view="myView"
    :data="myEvents"
    :resources="myResources"
    @cell-hover-in="handleCellHoverIn"
    @cell-hover-out="handleCellHoverOut"
  >
    <template #cell="{ date }">
      <div
        v-if="hoverDate && date.getTime() === hoverDate.getTime()"
        class="mds-highlight-col-hover"
      />
    </template>

    <template #sidebar="resource">
      <div>{{ resource.name }} Sidebar</div>
    </template>

    <template #timelineDay="{ date }">
      <div
        :class="[
          'mds-highlight-day-content',
          hoverDate && date.getTime() === hoverDate.getTime() && 'mds-highlight-col-hover'
        ]"
      >
        {{ formatDate('D DDD', date) }}
      </div>
    </template>

    <template #dayFooter="{ date }">
      <div
        :class="[
          'mds-highlight-day-content',
          hoverDate && date.getTime() === hoverDate.getTime() && 'mds-highlight-col-hover'
        ]"
      >
        {{ formatDate('D DDD', date) }}
      </div>
    </template>
  </MbscEventcalendar>

  <MbscPopup
    :anchor="anchor"
    :closeOnScroll="true"
    display="anchored"
    :focusOnClose="false"
    :isOpen="isPopupOpen"
    :scrollLock="false"
    :showOverlay="false"
  >
    <div v-if="hoverResource && hoverDate" class="mds-highlight-tooltip">
      <div class="mds-highlight-tooltip-name">{{ hoverResource.name }}</div>
      <div class="mds-highlight-tooltip-date">{{ formatDate('MMM DD, YYYY', hoverDate) }}</div>
    </div>
  </MbscPopup>
</template>

<style>
.mds-highlight-hover .mbsc-timeline-sidebar-col {
  width: 170px;
}

.mds-highlight-hover .mbsc-timeline-sidebar-resource-title {
  font-weight: 500;
}

.mds-highlight-hover .mds-highlight-row-hover,
.mds-highlight-hover .mds-highlight-col-hover {
  background: rgba(220, 220, 220, 0.25);
}

.mds-highlight-col-hover {
  position: absolute;
  inset: 0;
  background: transparent;
  pointer-events: none;
  box-sizing: border-box;
}

.mds-highlight-day-content {
  font-size: 14px;
  height: 30px;
  text-align: center;
  line-height: 30px;
  position: relative;
}

.mds-highlight-tooltip {
  padding: 5px;
  font-size: 14px;
  line-height: 1.4;
}

.mds-highlight-tooltip-name {
  font-weight: 600;
  margin-bottom: 5px;
}

.mds-highlight-tooltip-date {
  color: #888;
}
</style>
```

### SFC TS

```vue
<script setup lang="ts">
import { formatDate, MbscEventcalendar, MbscPopup, setOptions } from '@mobiscroll/vue'
import type {
  MbscCalendarEvent,
  MbscCellHoverEvent,
  MbscEventcalendarView,
  MbscResource
} from '@mobiscroll/vue'
import { ref } from 'vue'

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

const anchor = ref<HTMLElement>()
const hoverDate = ref<Date | null>(null)
const hoverResource = ref<MbscResource | null>(null)
const isPopupOpen = ref<boolean>(false)

const myView: MbscEventcalendarView = {
  timeline: {
    type: 'month',
    resolutionHorizontal: 'day'
  }
}

const myEvents = ref<MbscCalendarEvent[]>([
  { start: '2026-10-02T00:00', end: '2026-10-05T00:00', title: 'Event 1', resource: 1 },
  { start: '2026-10-10T09:00', end: '2026-10-15T15:00', title: 'Event 2', resource: 3 },
  { start: '2026-10-12T00:00', end: '2026-10-14T00:00', title: 'Event 3', resource: 4 },
  { start: '2026-10-15T07:00', end: '2026-10-20T12:00', title: 'Event 4', resource: 5 },
  { start: '2026-10-03T00:00', end: '2026-10-10T00:00', title: 'Event 5', resource: 6 },
  { start: '2026-10-10T08:00', end: '2026-10-11T20:00', title: 'Event 6', resource: 7 },
  { start: '2026-10-22T00:00', end: '2026-10-28T00:00', title: 'Event 7', resource: 7 },
  { start: '2026-10-08T00:00', end: '2026-10-13T00:00', title: 'Event 8', resource: 15 },
  { start: '2026-10-25T00:00', end: '2026-10-27T00:00', title: 'Event 9', resource: 10 },
  { start: '2026-10-20T00:00', end: '2026-10-23T00:00', title: 'Event 10', resource: 12 }
])

const myResources = ref<MbscResource[]>([
  { id: 1, name: 'Resource A', color: '#e20000', cssClass: '' },
  { id: 2, name: 'Resource B', color: '#76e083', cssClass: '' },
  { id: 3, name: 'Resource C', color: '#4981d6', cssClass: '' },
  { id: 4, name: 'Resource D', color: '#e25dd2', cssClass: '' },
  { id: 5, name: 'Resource E', color: '#1dab2f', cssClass: '' },
  { id: 6, name: 'Resource F', color: '#d6d145', cssClass: '' },
  { id: 7, name: 'Resource G', color: '#34c8e0', cssClass: '' },
  { id: 8, name: 'Resource H', color: '#9dde46', cssClass: '' },
  { id: 9, name: 'Resource I', color: '#166f6f', cssClass: '' },
  { id: 10, name: 'Resource J', color: '#f7961e', cssClass: '' },
  { id: 11, name: 'Resource K', color: '#34c8e0', cssClass: '' },
  { id: 12, name: 'Resource L', color: '#af0000', cssClass: '' },
  { id: 13, name: 'Resource M', color: '#446f1c', cssClass: '' },
  { id: 14, name: 'Resource N', color: '#073138', cssClass: '' },
  { id: 15, name: 'Resource O', color: '#4caf00', cssClass: '' }
])

function handleCellHoverIn(args: MbscCellHoverEvent) {
  const resId = args.resource.id
  myResources.value = myResources.value.map((r) => ({
    ...r,
    cssClass: r.id === resId ? 'mds-highlight-row-hover' : ''
  }))

  hoverDate.value = args.date
  hoverResource.value = myResources.value.find((r) => r.id === resId) || null
  anchor.value = args.domEvent.target as HTMLElement
  isPopupOpen.value = true
}

function handleCellHoverOut() {
  hoverDate.value = null
  hoverResource.value = null
  myResources.value = myResources.value.map((r) => ({ ...r, cssClass: '' }))
  isPopupOpen.value = false
}
</script>

<template>
  <MbscEventcalendar
    cssClass="mds-highlight-hover"
    :view="myView"
    :data="myEvents"
    :resources="myResources"
    @cell-hover-in="handleCellHoverIn"
    @cell-hover-out="handleCellHoverOut"
  >
    <template #cell="{ date }">
      <div
        v-if="hoverDate && date.getTime() === hoverDate.getTime()"
        class="mds-highlight-col-hover"
      />
    </template>

    <template #sidebar="resource">
      <div>{{ resource.name }} Sidebar</div>
    </template>

    <template #timelineDay="{ date }">
      <div
        :class="[
          'mds-highlight-day-content',
          hoverDate && date.getTime() === hoverDate.getTime() && 'mds-highlight-col-hover'
        ]"
      >
        {{ formatDate('D DDD', date) }}
      </div>
    </template>

    <template #dayFooter="{ date }">
      <div
        :class="[
          'mds-highlight-day-content',
          hoverDate && date.getTime() === hoverDate.getTime() && 'mds-highlight-col-hover'
        ]"
      >
        {{ formatDate('D DDD', date) }}
      </div>
    </template>
  </MbscEventcalendar>

  <MbscPopup
    :anchor="anchor"
    :closeOnScroll="true"
    display="anchored"
    :focusOnClose="false"
    :isOpen="isPopupOpen"
    :scrollLock="false"
    :showOverlay="false"
  >
    <div v-if="hoverResource && hoverDate" class="mds-highlight-tooltip">
      <div class="mds-highlight-tooltip-name">{{ hoverResource.name }}</div>
      <div class="mds-highlight-tooltip-date">{{ formatDate('MMM DD, YYYY', hoverDate) }}</div>
    </div>
  </MbscPopup>
</template>

<style>
.mds-highlight-hover .mbsc-timeline-sidebar-col {
  width: 170px;
}

.mds-highlight-hover .mbsc-timeline-sidebar-resource-title {
  font-weight: 500;
}

.mds-highlight-hover .mds-highlight-row-hover,
.mds-highlight-hover .mds-highlight-col-hover {
  background: rgba(220, 220, 220, 0.25);
}

.mds-highlight-col-hover {
  position: absolute;
  inset: 0;
  background: transparent;
  pointer-events: none;
  box-sizing: border-box;
}

.mds-highlight-day-content {
  font-size: 14px;
  height: 30px;
  text-align: center;
  line-height: 30px;
  position: relative;
}

.mds-highlight-tooltip {
  padding: 5px;
  font-size: 14px;
  line-height: 1.4;
}

.mds-highlight-tooltip-name {
  font-weight: 600;
  margin-bottom: 5px;
}

.mds-highlight-tooltip-date {
  color: #888;
}
</style>
```

## Implementation notes

- Use `timeline: { type: 'month', resolutionHorizontal: 'day' }` - a monthly view with one column per day.
- Define 15 resources (A-O) with `id`, `name`, and `color`.
- Add 10 events with `dyndatetime` offsets spread across the current month.
- Track the currently hovered cell in a `hoverDateTime` variable (set on hover in, cleared on hover out).
- **Row highlight** via `cssClass` on resource objects:
  - `onCellHoverIn`: iterate the resources array, set `cssClass: 'mds-highlight-row-hover'` on the resource whose `id` matches `args.resource.id`, clear `cssClass` on all others. JS/jQuery: call `calendar.setOptions({ resources: myResources.slice() })` to push the change and trigger a re-render. React/Angular/Vue: instead update the state/binding feeding the `resources` prop directly (e.g. `setResources(myResources.slice())`).
  - `onCellHoverOut`: clear all `cssClass` values. JS/jQuery: wrap `setOptions` in a `setTimeout` (no delay) so the render callbacks reset before the DOM updates. React/Angular/Vue: wrap the equivalent `resources` state/binding update (e.g. `setResources(myResources.slice())`) in the same `setTimeout` (no delay) so the render callbacks reset before the DOM updates.
- **Column highlight** via render callbacks that compare each cell's date to `hoverDateTime`:
  - `renderCell` (Angular: `cellTemplate`, Vue: `#cell`): when `args.date` matches `hoverDateTime`, return a full-cell overlay `<div class="mds-highlight-col-hover">` (positioned absolute, `inset: 0`, `pointer-events: none`); otherwise return an empty string.
  - `renderTimelineDay` (Angular: `timelineDayTemplate`, Vue: `#timelineDay`) and `renderDayFooter` (Angular: `dayFooterTemplate`, Vue: `#dayFooter`): always render a custom day content div showing `formatDate('D DDD', args.date)`. When the date matches `hoverDateTime`, add `mds-highlight-col-hover` to the div's class.
  - `renderSidebar` (Angular: `sidebarTemplate`, Vue: `#sidebar`): renders the resource name with a " Sidebar" suffix.
- **Tooltip popup** (`Popup`, `display: 'anchored'`, `showOverlay: false`, `scrollLock: false`, `focusOnClose: false`, `closeOnScroll: true`):
  - `onCellHoverIn`: set `anchor: args.domEvent.target`, populate the tooltip with `args.resource.name` and `formatDate('MMM DD, YYYY', args.date)`, then open.
  - `onCellHoverOut`: close the popup.
- **CSS**: `.mds-highlight-row-hover` and `.mds-highlight-col-hover` share the same background `rgba(220,220,220,0.25)` - the row class is applied via the resource `cssClass` property (Mobiscroll renders it on the row container), and the column class is applied via the overlay div in `renderCell` and the class added in `renderTimelineDay`/`renderDayFooter`.

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

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

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

## Related demos

- Next: [Custom Time Range Backgrounds](https://demo.mobiscroll.com/vue/timeline/colors-invalids-css-class.md) - Style time range backgrounds and blocked periods on a Vue Timeline using CSS classes — mark recurring hours or special days.
