---
title: "Vue Timeline Event Search Sidebar Example | Mobiscroll"
component: "Timeline"
framework: "Vue"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/vue/timeline/searching-events-in-sidebar"
---

# Event Search Sidebar - Vue Timeline demo

Search and filter Vue timeline events in real time — results appear in a sidebar agenda as you type, clicking the event navigates to date. For Vue and Nuxt.

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

## Description

Inline search can be easily implemented with the help of a separate [agenda](https://demo.mobiscroll.com/vue/agenda) instance. This example is relying on a single API endpoint for getting the data onto the primary timeline view and also for getting the filtered data based on the search terms.

[Events can be filtered in real time](https://demo.mobiscroll.com/vue/scheduler/resource-filtering-in-header) so using an agenda view for the search results is an easy choice. It provides all the necessary styling and advanced features that you might need to customize the experience.

Alternatively, search can be implemented in the header using a similar search box with an [agenda listed in a popup](https://demo.mobiscroll.com/vue/eventcalendar/searching-events-in-popup) instead of rendered inline.

## What this demo shows

- A desktop monthly timeline where days are arranged horizontally and resources are listed as rows on the left.
- **Search sidebar** The left sidebar contains a search field with a search icon and the `Search events` placeholder text.
- **Search results** Typing in the search field displays matching events in an agenda-style list below the input.
- **Agenda results** Search results are grouped by date, and each event row shows a colored marker, the event title, and the event type, such as all-day or timed.
- **Result selection** Clicking an event in the agenda list navigates the timeline to the date that contain the selected event.
- **Empty state** When the search returns no matches, a `No events` message appears below the search box.
- **Header navigation** The month and year label opens date navigation, while the previous and next arrows move between month and the Today button returns to the current date.
- **Month view** The strip below the header shows the days of the selected month, with the current date highlighted.
- **Resources** Multiple resources are shown as separate timeline rows.
- **Event labels** Events are shown as colored labels with a bold title.
- **Date positioning** Events are positioned by their assigned resource and exact date range.
- **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 time and resources.

## Best for

- **Searchable timeline interfaces** Timelines where users need to find specific events without leaving the main timeline view.
- **Employee scheduling** Workforce and shift planning tools where users search for people, absences, or schedule entries across a larger calendar.
- **Project and team planning** Planning tools where users search by keyword, event type, or participant while keeping the broader timeline visible.

## 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
- [`navigateToEvent`](https://mobiscroll.com/docs/vue/eventcalendar/api#method-navigateToEvent) - method
- [`data`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-resources) - option
- [`showControls`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-showControls) - option
- [`view`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-view) - option
- [`event-click`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onEventClick) - event
- [`clickToCreate`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToResize) - option
- [`selectMultipleEvents`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-selectMultipleEvents) - option
- [`selectedEvents`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-selectedEvents) - option
- [`page-loading`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onPageLoading) - event

## Code

### SFC JS

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

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

const calEvents = ref([])
const listEvents = ref([])
const selectedEvent = ref([])
const displayResults = ref(false)

const calInst = ref(null)
const timer = ref(null)

const calView = { timeline: { type: 'month', eventDisplay: 'fill' } }
const listView = { agenda: { type: 'year', size: 5 } }

const myResources = [
  { id: 1, name: 'Resource 1', color: '#fdf500' },
  { id: 2, name: 'Resource 2', color: '#ff4600' },
  { id: 3, name: 'Resource 3', color: '#ff0101' },
  { id: 4, name: 'Resource 4', color: '#239a21' },
  { id: 5, name: 'Resource 5', color: '#8f1ed6' },
  { id: 6, name: 'Resource 6', color: '#01adff' }
]

function handleInputChange(ev) {
  const searchText = ev.target.value

  clearTimeout(timer.value)
  timer.value = setTimeout(() => {
    if (searchText.length > 0) {
      getJson(
        'https://trial.mobiscroll.com/searchevents-timeline/?text=' + searchText,
        (data) => {
          listEvents.value = data
          displayResults.value = true
        },
        'jsonp'
      )
    } else {
      displayResults.value = false
    }
  }, 200)
}

function handlePageLoading(args) {
  const start = formatDate('YYYY-MM-DD', args.viewStart)
  const end = formatDate('YYYY-MM-DD', args.viewEnd)

  setTimeout(() => {
    getJson(
      'https://trial.mobiscroll.com/searchevents-timeline/?start=' + start + '&end=' + end,
      (data) => {
        calEvents.value = data
      },
      'jsonp'
    )
  })
}

function handleEventClick(args) {
  selectedEvent.value = [args.event]
  calInst.value.instance.navigateToEvent(args.event)
}
</script>

<template>
  <MbscPage cssClass="mds-full-height">
    <div class="mds-full-height mbsc-flex">
      <div class="mds-search-sidebar mbsc-flex-col mbsc-flex-none">
        <MbscInput
          autocomplete="off"
          startIcon="material-search"
          inputStyle="outline"
          placeholder="Search events"
          @input="handleInputChange"
        />
        <MbscEventcalendar
          v-if="displayResults"
          :data="listEvents"
          :resources="myResources"
          :showControls="false"
          :view="listView"
          @event-click="handleEventClick"
        />
      </div>
      <div class="mds-search-calendar mbsc-flex-1-1">
        <MbscEventcalendar
          ref="calInst"
          :clickToCreate="false"
          :data="calEvents"
          :dragToCreate="false"
          :dragToMove="false"
          :dragToResize="false"
          :resources="myResources"
          :selectMultipleEvents="true"
          :selectedEvents="selectedEvent"
          :view="calView"
          @page-loading="handlePageLoading"
        />
      </div>
    </div>
  </MbscPage>
</template>

<style>
.mds-full-height {
  height: 100%;
}

.mds-search-calendar {
  border-left: 1px solid #ccc;
  overflow: hidden;
}

.mds-search-sidebar {
  width: 350px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-ios {
  margin-top: 27px;
  margin-bottom: 26px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-material {
  margin-top: 26px;
  margin-bottom: 26px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-windows {
  margin-top: 35px;
  margin-bottom: 35px;
}

@media (min-width: 1135px) {
  .mds-search-sidebar .mbsc-textfield-wrapper.mbsc-windows {
    margin-top: 40px;
    margin-bottom: 40px;
  }
}
</style>
```

### SFC TS

```vue
<script setup lang="ts">
import {
  formatDate,
  getJson,
  MbscEventcalendar,
  MbscInput,
  MbscPage,
  setOptions
} from '@mobiscroll/vue'
import type {
  MbscCalendarEvent,
  MbscEventcalendarView,
  MbscEventClickEvent,
  MbscPageLoadingEvent,
  MbscResource
} from '@mobiscroll/vue'
import { ref } from 'vue'

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

const calEvents = ref<MbscCalendarEvent[]>([])
const listEvents = ref<MbscCalendarEvent[]>([])
const selectedEvent = ref<MbscCalendarEvent[]>([])
const displayResults = ref(false)

const calInst = ref<typeof MbscEventcalendar>()
const timer = ref<ReturnType<typeof setTimeout>>()

const calView: MbscEventcalendarView = { timeline: { type: 'month', eventDisplay: 'fill' } }
const listView: MbscEventcalendarView = { agenda: { type: 'year', size: 5 } }

const myResources: MbscResource[] = [
  { id: 1, name: 'Resource 1', color: '#fdf500' },
  { id: 2, name: 'Resource 2', color: '#ff4600' },
  { id: 3, name: 'Resource 3', color: '#ff0101' },
  { id: 4, name: 'Resource 4', color: '#239a21' },
  { id: 5, name: 'Resource 5', color: '#8f1ed6' },
  { id: 6, name: 'Resource 6', color: '#01adff' }
]

function handleInputChange(ev: Event) {
  const input = ev.target as HTMLInputElement
  const searchText = input.value

  clearTimeout(timer.value)
  timer.value = setTimeout(() => {
    if (searchText.length > 0) {
      getJson(
        'https://trial.mobiscroll.com/searchevents-timeline/?text=' + searchText,
        (data: MbscCalendarEvent[]) => {
          listEvents.value = data
          displayResults.value = true
        },
        'jsonp'
      )
    } else {
      displayResults.value = false
    }
  }, 200)
}

function handlePageLoading(args: MbscPageLoadingEvent) {
  const start = formatDate('YYYY-MM-DD', args.viewStart)
  const end = formatDate('YYYY-MM-DD', args.viewEnd)

  setTimeout(() => {
    getJson(
      'https://trial.mobiscroll.com/searchevents-timeline/?start=' + start + '&end=' + end,
      (data: MbscCalendarEvent[]) => {
        calEvents.value = data
      },
      'jsonp'
    )
  })
}

function handleEventClick(args: MbscEventClickEvent) {
  selectedEvent.value = [args.event]
  calInst.value?.instance.navigateToEvent(args.event)
}
</script>

<template>
  <MbscPage cssClass="mds-full-height">
    <div class="mds-full-height mbsc-flex">
      <div class="mds-search-sidebar mbsc-flex-col mbsc-flex-none">
        <MbscInput
          autocomplete="off"
          startIcon="material-search"
          inputStyle="outline"
          placeholder="Search events"
          @input="handleInputChange"
        />
        <MbscEventcalendar
          v-if="displayResults"
          :data="listEvents"
          :resources="myResources"
          :showControls="false"
          :view="listView"
          @event-click="handleEventClick"
        />
      </div>
      <div class="mds-search-calendar mbsc-flex-1-1">
        <MbscEventcalendar
          ref="calInst"
          :clickToCreate="false"
          :data="calEvents"
          :dragToCreate="false"
          :dragToMove="false"
          :dragToResize="false"
          :resources="myResources"
          :selectMultipleEvents="true"
          :selectedEvents="selectedEvent"
          :view="calView"
          @page-loading="handlePageLoading"
        />
      </div>
    </div>
  </MbscPage>
</template>

<style>
.mds-full-height {
  height: 100%;
}

.mds-search-calendar {
  border-left: 1px solid #ccc;
  overflow: hidden;
}

.mds-search-sidebar {
  width: 350px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-ios {
  margin-top: 27px;
  margin-bottom: 26px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-material {
  margin-top: 26px;
  margin-bottom: 26px;
}

.mds-search-sidebar .mbsc-textfield-wrapper.mbsc-windows {
  margin-top: 35px;
  margin-bottom: 35px;
}

@media (min-width: 1135px) {
  .mds-search-sidebar .mbsc-textfield-wrapper.mbsc-windows {
    margin-top: 40px;
    margin-bottom: 40px;
  }
}
</style>
```

## Implementation notes

- Use a two-panel layout: a left sidebar containing the search input and the results list, and a right panel containing the main timeline calendar.
- The sidebar holds two elements: a Mobiscroll `Input` with `startIcon="material-search"`, `inputStyle="outline"`, `autoComplete="off"`, `placeholder="Search events"`; and a second `Eventcalendar` instance (the search results list) that is only shown when there are results.
- Configure the **search results** `Eventcalendar` with `view: { agenda: { type: 'year', size: 5 } }`, `showControls={false}`, and the same 6 resources as the main calendar. Show it only when there are results to display.
- Configure the **main timeline** `Eventcalendar` with `view: { timeline: { type: 'month', eventDisplay: 'fill' } }`, `clickToCreate={false}`, `dragToCreate={false}`, `dragToMove={false}`, `dragToResize={false}`, and `selectMultipleEvents={true}`.
- Define 6 generic resources (Resource 1-6) with `id`, `name`, and `color`, shared by both calendar instances.
- **Debounced search**: on each input change, clear any pending timeout and set a new 200ms timer. When the timeout fires and the search text is non-empty, call `getJson` to `https://trial.mobiscroll.com/searchevents-timeline/?text=<searchText>` and populate the agenda list, then reveal the results panel. When the text is cleared, hide the results panel without making a request. (Angular: use `HttpClient.jsonp()` instead of `getJson`.)
- **Page-level data loading**: handle `onPageLoading` on the main calendar. Format `args.viewStart` and `args.viewEnd` as `'YYYY-MM-DD'` using `formatDate`, then call `getJson` (Angular: `HttpClient.jsonp`) to `https://trial.mobiscroll.com/searchevents-timeline/?start=<start>&end=<end>` and set the main calendar's events. Wrap the `getJson` call in `setTimeout` with no delay to defer it past the current rendering cycle.
- **Navigating on result click**: handle `onEventClick` on the search results agenda. Call `navigateToEvent(args.event)` on the main calendar instance to jump to that event's date, then set `selectedEvents` to `[args.event]` to highlight it; for the imperative API, call `calendarInstance.setSelectedEvents([args.event])` directly.
- Keep a ref/`@ViewChild` reference to the main calendar instance to call `navigateToEvent` imperatively.

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

- Previous: [Multiple Timezone Support](https://demo.mobiscroll.com/vue/timeline/multiple-timezone-support.md) - Add a timezone-switcher dropdown to Vue Timeline header — users change display timezone on the fly, with data timezones configured independently.
- Next: [External Date Navigation](https://demo.mobiscroll.com/vue/timeline/navigate-view-from-external-calendar.md) - Use a two-panel Vue Timeline navigated by an external date picker — selecting a date syncs the timeline and the picker instantly.
