---
title: "Vue Select Templating Example | Mobiscroll"
component: "Select"
framework: "Vue"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/vue/select/item-templating"
---

# Templating - Vue Select demo

Vue select component & dropdown with templating capability. Render custom content for each item, like image & text. For Vue and Nuxt.

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

## Description

By default the select takes the `item.text` and `item.value` of the [`data` array](https://mobiscroll.com/docs/vue/select/api#opt-data) items and populates the select. Besides the basic text/value interpretation you can write custom templates to render any custom markup as a scrollable list.

With the help of the [`item`](https://mobiscroll.com/docs/vue/select/api#slot-item) template you can write a custom template where any `data` field can be used. You'll also want to make sure that the [`itemHeight`](https://mobiscroll.com/docs/vue/select/api#opt-itemHeight) is set accordingly.

## What this demo shows

- Shows a single-value select with custom item templating.
- **Select input** Focusing or clicking the input opens the picker below it.
- **Popup behavior** Clicking outside the picker closes it.
- **Picker content** Each option displays album artwork, the album title, release year, and artist instead of text-only content.
- **Scrolling** The dropdown supports scrolling through the full list of options.
- **Hover state** Hovering over an option highlights it.
- **Selection** Selecting an option marks it with a checkmark to indicate the current value.
- **Input value** Selecting an option updates the associated input with that value.

## Best for

- **Media catalogs** Show cover artwork alongside titles, creators, release dates, or other metadata.
- **Product selectors** Pair product thumbnails with names, variants, prices, or availability details.
- **People pickers** Display avatars with names, roles, teams, or other identifying information.
- **Location selectors** Combine place names with flags, icons, addresses, or time zone details.
- **Status and category selectors** Add icons, color indicators, or supporting descriptions to make options easier to distinguish.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/vue/select/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/vue/select/api#opt-themeVariant) - option
- [`data`](https://mobiscroll.com/docs/vue/select/api#opt-data) - option
- [`itemHeight`](https://mobiscroll.com/docs/vue/select/api#opt-itemHeight) - option
- [`label`](https://mobiscroll.com/docs/vue/select/api#opt-label) - option
- [`display`](https://mobiscroll.com/docs/vue/select/api#opt-display) - option
- [`inputStyle`](https://mobiscroll.com/docs/vue/select/api#opt-inputStyle) - option
- [`labelStyle`](https://mobiscroll.com/docs/vue/select/api#opt-labelStyle) - option

## Code

### SFC JS

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

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

const myData = ref([
  {
    text: 'Mercury – Act 1',
    year: '2021',
    artist: 'Imagine Dragons',
    value: '56243',
    img: 'Mercury_Act_1'
  },
  {
    text: 'Divide',
    year: '2017',
    artist: 'Ed Sheeran',
    value: '18659',
    img: 'Divide'
  },
  {
    text: 'Evolution',
    year: '2018',
    artist: 'Disturbed',
    value: '88459',
    img: 'Evolution'
  },
  {
    text: 'Future Nostalgia',
    year: '2020',
    artist: 'Dua Lipa',
    value: '65422',
    img: 'Future_Nostalgia'
  },
  {
    text: 'Blue Banisters',
    year: '2021',
    artist: 'Lana Del Rey',
    value: '67111',
    img: 'Blue_Banisters'
  },
  {
    text: 'Human',
    year: '2021',
    artist: 'OneRepublic',
    value: '60589',
    img: 'Human'
  },
  {
    text: 'Kamikaze',
    year: '2018',
    artist: 'Eminem',
    value: '42122',
    img: 'Kamikaze'
  },
  {
    text: 'Simulation Theory',
    year: '2018',
    artist: 'Muse',
    value: '80040',
    img: 'Simulation_Theory'
  },
  {
    text: 'The Nothing',
    year: '2019',
    artist: 'Korn',
    value: '46611',
    img: 'Nothing'
  }
])
</script>

<template>
  <MbscSelect
    :data="myData"
    :itemHeight="64"
    label="Albums"
    display="anchored"
    inputStyle="box"
    labelStyle="stacked"
    placeholder="Please select..."
  >
    <template #item="item">
      <div class="md-item-template">
        <img
          class="md-item-template-img"
          :src="'https://img.mobiscroll.com/demos/' + item.data.img + '.png'"
          alt="Cover"
        />
        <div class="md-item-template-title">
          <span>{{ item.data.text }}</span>
          <span class="md-item-template-year">{{ ' (' + item.data.year + ')' }}</span>
        </div>
        <div class="md-item-template-artist">{{ 'by ' + item.data.artist }}</div>
      </div>
    </template>
  </MbscSelect>
</template>

<style>
.md-item-template {
  padding: 10px 10px 10px 54px;
  position: relative;
  text-align: left;
  line-height: normal;
}

.md-item-template-img {
  position: absolute;
  top: 50%;
  left: 0;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  border-radius: 4px;
}

.md-item-template-title {
  font-weight: 600;
  font-size: 15px;
  line-height: 24px;
}

.md-item-template-artist {
  font-size: 14px;
  opacity: 0.8;
  line-height: 20px;
}

.mbsc-scroller-wheel-item-2d .md-item-template {
  transform: scale(1.05);
}
</style>
```

### SFC TS

```vue
<script setup lang="ts">
import { MbscSelect, setOptions } from '@mobiscroll/vue'
import { ref } from 'vue'

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

const myData = ref([
  {
    text: 'Mercury – Act 1',
    year: '2021',
    artist: 'Imagine Dragons',
    value: '56243',
    img: 'Mercury_Act_1'
  },
  {
    text: 'Divide',
    year: '2017',
    artist: 'Ed Sheeran',
    value: '18659',
    img: 'Divide'
  },
  {
    text: 'Evolution',
    year: '2018',
    artist: 'Disturbed',
    value: '88459',
    img: 'Evolution'
  },
  {
    text: 'Future Nostalgia',
    year: '2020',
    artist: 'Dua Lipa',
    value: '65422',
    img: 'Future_Nostalgia'
  },
  {
    text: 'Blue Banisters',
    year: '2021',
    artist: 'Lana Del Rey',
    value: '67111',
    img: 'Blue_Banisters'
  },
  {
    text: 'Human',
    year: '2021',
    artist: 'OneRepublic',
    value: '60589',
    img: 'Human'
  },
  {
    text: 'Kamikaze',
    year: '2018',
    artist: 'Eminem',
    value: '42122',
    img: 'Kamikaze'
  },
  {
    text: 'Simulation Theory',
    year: '2018',
    artist: 'Muse',
    value: '80040',
    img: 'Simulation_Theory'
  },
  {
    text: 'The Nothing',
    year: '2019',
    artist: 'Korn',
    value: '46611',
    img: 'Nothing'
  }
])
</script>

<template>
  <MbscSelect
    :data="myData"
    :itemHeight="64"
    label="Albums"
    display="anchored"
    inputStyle="box"
    labelStyle="stacked"
    placeholder="Please select..."
  >
    <template #item="item">
      <div class="md-item-template">
        <img
          class="md-item-template-img"
          :src="'https://img.mobiscroll.com/demos/' + item.data.img + '.png'"
          alt="Cover"
        />
        <div class="md-item-template-title">
          <span>{{ item.data.text }}</span>
          <span class="md-item-template-year">{{ ' (' + item.data.year + ')' }}</span>
        </div>
        <div class="md-item-template-artist">{{ 'by ' + item.data.artist }}</div>
      </div>
    </template>
  </MbscSelect>
</template>

<style>
.md-item-template {
  padding: 10px 10px 10px 54px;
  position: relative;
  text-align: left;
  line-height: normal;
}

.md-item-template-img {
  position: absolute;
  top: 50%;
  left: 0;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  border-radius: 4px;
}

.md-item-template-title {
  font-weight: 600;
  font-size: 15px;
  line-height: 24px;
}

.md-item-template-artist {
  font-size: 14px;
  opacity: 0.8;
  line-height: 20px;
}

.mbsc-scroller-wheel-item-2d .md-item-template {
  transform: scale(1.05);
}
</style>
```

## Implementation notes

- By default the select renders each `data` item using only its `text`/`value` fields; any additional field on a `data` item (here `year`, `artist`, `img`) is ignored unless a custom item template is supplied.
- `data` items in this demo carry `text`, `value`, plus custom `year`, `artist`, and `img` fields - all of which the custom template reads off `item.data`.
- Custom templating is the mechanism, and its name and shape differ per framework:
  - **React**: a `renderItem` prop takes a function `(item: MbscSelectItemData) => JSX.Element`; the function reads `item.data.text`/`.year`/`.artist`/`.img` and returns markup built from those fields (e.g. an `<img>` sourced from `'https://img.mobiscroll.com/demos/' + data.img + '.png'`).
  - **Angular**: an `[itemTemplate]="itemTemp"` input points at a named `<ng-template #itemTemp let-item>`, with `item.data.*` interpolated directly in the template (`{{item.data.text}}`, `[src]="'...' + item.data.img + '.png'"`).
  - **Vue**: the `#item` named slot on `<MbscSelect>` receives `item` as the slot prop, with `item.data.*` used inside `{{ }}` interpolations and `:src` bindings.
  - **JS/jQuery**: a `renderItem` function option (inside `.select({ ... })`) takes `(item)` and returns an HTML string built via concatenation of `item.data.*` fields.
- `itemHeight` (here `64`) must be set to the actual pixel height the custom row renders at - this component does not auto-measure custom template content, so a mismatch causes clipped or overlapping rows during scrolling.
- The album artwork itself is not a select feature - it's a plain `<img>` inside the custom template, sourced from a fixed `https://img.mobiscroll.com/demos/<img>.png` naming convention.
- `display="anchored"` opens the picker as a dropdown anchored to the input; `inputStyle`/`labelStyle`/`placeholder` are cosmetic input-decoration options independent of templating.

## 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: [Country Dropdown](https://demo.mobiscroll.com/vue/select/country-picker.md) - Vue Country picker scroller select for mobile/tablet. Alphabetical ordering, jump to value and filtering is supported.
