---
title: "React Select Templating Example | Mobiscroll"
component: "Select"
framework: "React"
library_version: "6.2.0"
url: "https://demo.mobiscroll.com/react/select/item-templating"
---

# Templating - React Select demo

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

- [Live demo](https://demo.mobiscroll.com/react/select/item-templating)
- [View React JS code on GitHub](https://github.com/acidb/mobiscroll-demos-react/tree/main/src/demos/pickers/select/item-templating)
- [View React TS code on GitHub](https://github.com/acidb/mobiscroll-demos-react-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), [Vue](https://demo.mobiscroll.com/vue/select/item-templating.md)

## Description

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

With the help of the [`renderItem` option](https://mobiscroll.com/docs/react/select/api#renderer-renderItem) you can write a function that returns the custom item markup. Any `data` field can be used for the template. You'll also want to make sure that the [`itemHeight`](https://mobiscroll.com/docs/react/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/react/select/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/react/select/api#opt-themeVariant) - option
- [`data`](https://mobiscroll.com/docs/react/select/api#opt-data) - option
- [`display`](https://mobiscroll.com/docs/react/select/api#opt-display) - option
- [`inputStyle`](https://mobiscroll.com/docs/react/select/api#opt-inputStyle) - option
- [`itemHeight`](https://mobiscroll.com/docs/react/select/api#opt-itemHeight) - option
- [`label`](https://mobiscroll.com/docs/react/select/api#opt-label) - option
- [`labelStyle`](https://mobiscroll.com/docs/react/select/api#opt-labelStyle) - option
- [`renderItem`](https://mobiscroll.com/docs/react/select/api#renderer-renderItem) - renderer

## Code

### JSX

```jsx
import { Select, setOptions } from '@mobiscroll/react';
import { useCallback, useMemo } from 'react';

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

function App() {
  const myData = useMemo(
    () => [
      {
        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',
      },
    ],
    [],
  );

  const renderCustomItem = useCallback((item) => {
    const data = item.data;
    return (
      <div className="md-item-template">
        <img className="md-item-template-img" src={'https://img.mobiscroll.com/demos/' + data.img + '.png'} alt="Cover" />
        <div className="md-item-template-title">
          <span>{data.text}</span>
          <span className="md-item-template-year">{' (' + data.year + ')'}</span>
        </div>
        <div className="md-item-template-artist">{'by ' + data.artist}</div>
      </div>
    );
  }, []);

  return (
    <Select
      data={myData}
      display="anchored"
      inputStyle="outline"
      itemHeight={64}
      label="Albums"
      labelStyle="stacked"
      placeholder="Please select..."
      renderItem={renderCustomItem}
    />
  );
}

export default App;
```

### TSX

```tsx
import { MbscSelectItemData, Select, setOptions } from '@mobiscroll/react';
import { FC, useCallback } from 'react';

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

const myData = [
  {
    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',
  },
];

const App: FC = () => {
  const renderCustomItem = useCallback((item: MbscSelectItemData) => {
    const data = item.data;
    return (
      <div className="md-item-template">
        <img className="md-item-template-img" src={'https://img.mobiscroll.com/demos/' + data.img + '.png'} alt="Cover" />
        <div className="md-item-template-title">
          <span>{data.text}</span>
          <span className="md-item-template-year">{' (' + data.year + ')'}</span>
        </div>
        <div className="md-item-template-artist">{'by ' + data.artist}</div>
      </div>
    );
  }, []);

  return (
    <Select
      data={myData}
      display="anchored"
      inputStyle="outline"
      itemHeight={64}
      label="Albums"
      labelStyle="stacked"
      placeholder="Please select..."
      renderItem={renderCustomItem}
    />
  );
};
export default App;
```

### CSS

```css
.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);
}
```

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

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

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

## Related demos

- Next: [Country Dropdown](https://demo.mobiscroll.com/react/select/country-picker.md) - React Country picker scroller select for mobile/tablet. Alphabetical ordering, jump to value and filtering is supported.
