---
title: "Javascript Select Multiline select Example | Mobiscroll"
component: "Select"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/select/multiple-lines"
---

# Multiline select - JavaScript Select demo

Javascript Select scroller style demo supporting long text rendered in multiple rows. With smooth scrolling and native look & feel. Plain JavaScript API.

- [Live demo](https://demo.mobiscroll.com/javascript/select/multiple-lines)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/pickers/select/multiple-lines)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/select/multiple-lines.md), [Angular](https://demo.mobiscroll.com/angular/select/multiple-lines.md), [React](https://demo.mobiscroll.com/react/select/multiple-lines.md), [Vue](https://demo.mobiscroll.com/vue/select/multiple-lines.md)

## Description

Sometimes, the items of the select can get very long and they won't fit a single line. For those cases you can use the [custom item templating](https://demo.mobiscroll.com/javascript/select/item-templating) and [`itemHeight`](https://mobiscroll.com/docs/javascript/select/api#opt-itemHeight) to solve the rendering problems.

## What this demo shows

- Shows a single-value select with custom item templates that display options across multiple lines.
- **Opening and closing** Focusing or clicking the input opens the picker below it. Clicking outside the picker closes it.
- **Picker content** A predefined list of options appears in a dropdown-style popup, with each option formatted using a custom multiline template.
- **Hover state** Hovering over an option highlights it in the picker.
- **Selection** Selecting an option marks it with a checkmark to identify the current value.
- **Scrolling** The picker supports scrolling through the full list of options.
- **Input value** Selecting an option updates the input with the chosen value.

## Best for

- **Descriptive choices** Options that combine a primary label with supporting details or explanatory text.
- **People and account selection** Names that need secondary information, such as a role, team, email address, or account identifier.
- **Product and service selection** Items that include a name together with a variant, specification, or short description.
- **Location selection** Long place names or addresses that are easier to scan when displayed across multiple lines.

## Tutorial

```html
<label>
    Multiple lines
    <input mbsc-input id="my-select" data-dropdown="true" />
</label>
```

```js
mobiscroll.select('#my-select', {
    itemHeight: 60,
    maxWidth: 400,
    data: [
        { value: 1, text: 'Percentage of assets covered by systematic risk assessments (>99)' },
        { value: 2, text: 'Number of personal vacancies in the security roles required for ISMS (Nil)' },
        { value: 3, text: 'Time taken to grant, change and remove access privileges (Max. 2 hours)' },
        { value: 4, text: 'Percentage of agents covered by an effective security awareness program (100%)' },
        { value: 5, text: 'Number of security access violations (<2)' },
        { value: 6, text: 'Number of emergency changes (<5)' },
        { value: 7, text: 'Number of security incidents involving malicious code (Max. 2)' },
        { value: 8, text: 'Number of systems where security requirements are not met (Max. 2)' },
        { value: 9, text: 'Average turnaround time of incidents (Max. 2 hours)' },
        { value: 10, text: 'Number of pending actions to meet response and recovery requirements (Max. 5)' },
        { value: 11, text: 'Number of scheduled internal audits not done (Max. 1)' },
        { value: 12, text: 'Number of scheduled penetration tests not done (Max. 1)' },
        { value: 13, text: 'Number of overdue actions arising out of audit reports (Max. 5)' },
        { value: 14, text: 'Number of changes not carried out as per change control procedure (Max. 1)' }
    ],
    renderItem: function (item) {
        return '<div class="my-multi-lines-item"><span class="my-multi-lines-text">' +
            item.display + '</span></div>';
    },
    touchUi: false
});
```

```css
.my-multi-lines-item {
    font-size: 14px;
    white-space: initial;
    display: flex;
    height: 60px;
    line-height: normal;
}

.my-multi-lines-text {
    margin-top: auto;
    margin-bottom: auto;
}
```

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/select/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/select/api#opt-themeVariant) - option
- [`display`](https://mobiscroll.com/docs/javascript/select/api#opt-display) - option
- [`itemHeight`](https://mobiscroll.com/docs/javascript/select/api#opt-itemHeight) - option
- [`data`](https://mobiscroll.com/docs/javascript/select/api#opt-data) - option
- [`renderItem`](https://mobiscroll.com/docs/javascript/select/api#renderer-renderItem) - renderer

## Code

### JS

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

mobiscroll.select('#demo-multiple-lines', {
  display: 'anchored',
  itemHeight: 60,
  data: [
    {
      text: 'Percentage of assets covered by systematic risk assessments (>99)',
      value: 1,
    },
    {
      text: 'Number of personal vacancies in the security roles required for ISMS (Nil)',
      value: 2,
    },
    {
      text: 'Time taken to grant, change and remove access privileges (Max. 2 hours)',
      value: 3,
    },
    {
      text: 'Percentage of agents covered by an effective security awareness program (100%)',
      value: 4,
    },
    {
      text: 'Number of security access violations (<2)',
      value: 5,
    },
    {
      text: 'Number of emergency changes (<5)',
      value: 6,
    },
    {
      text: 'Number of security incidents involving malicious code (Max. 2)',
      value: 7,
    },
    {
      text: 'Number of systems where security requirements are not met (Max. 2)',
      value: 8,
    },
    {
      text: 'Average turnaround time of incidents (Max. 2 hours)',
      value: 9,
    },
    {
      text: 'Number of pending actions to meet response and recovery requirements (Max. 5)',
      value: 10,
    },
    {
      text: 'Number of scheduled internal audits not done (Max. 1)',
      value: 11,
    },
    {
      text: 'Number of scheduled penetration tests not done (Max. 1)',
      value: 12,
    },
    {
      text: 'Number of overdue actions arising out of audit reports (Max. 5)',
      value: 13,
    },
    {
      text: 'Number of changes not carried out as per change control procedure (Max. 1)',
      value: 14,
    },
  ],
  renderItem: function (item) {
    return '<div class="md-multiple-lines-item"><span class="md-multiple-lines-text">' + item.display + '</span></div>';
  },
});
```

### HTML

```html
<label>
    Multiline
    <input mbsc-input id="demo-multiple-lines" data-dropdown="true" data-input-style="box" data-label-style="stacked" placeholder="Please select..." />
</label>
```

### CSS

```css
.md-multiple-lines-item {
    font-size: 14px;
    white-space: initial;
    display: flex;
    height: 60px;
    line-height: normal;
}

.md-multiple-lines-text {
    margin-top: auto;
    margin-bottom: auto;
}
```

## Implementation notes

- `data` is an array of `{ value, text }` objects; long `text` strings are what forces the wrapped, multi-line rendering shown in this demo.
- `itemHeight` (number, px) sets a fixed row height for every option in the popup list - it must be increased from the default single-line height (e.g. to `60`) so a multi-line custom item template has room to render without clipping or overlapping neighboring rows.
- `maxWidth` (number, px) caps the popup's width (e.g. `400`) so long option text wraps within a readable column instead of stretching the picker edge to edge.
- Custom item markup is supplied per framework: JS/jQuery pass a `renderItem(item)` function option that returns an HTML string, using `item.display` for the option's resolved label; React passes a `renderItem` prop function that returns JSX, also reading `item.display`; Vue uses the `#item` scoped slot on `<MbscSelect>`, receiving the item as the slot prop and reading `item.display`; Angular passes `[itemTemplate]` pointing to an `<ng-template #itemTemp let-item>` and reads `item.display` via interpolation (`{{item.display}}`).
- `item.display` is the resolved/formatted label Mobiscroll computes for the option (distinct from the raw `item.text` on the data object) - templating code should read `.display`, not `.text`, to get the same value the default renderer would have shown.
- The custom item wrapper needs its own CSS to actually use the extra `itemHeight` (e.g. a flex container with `white-space: initial` and a height matching `itemHeight` so wrapped text is vertically centered) - this is regular page CSS, not a Select option.

## 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: [Image & text](https://demo.mobiscroll.com/javascript/select/image-text.md) - Javascript select with custom item templates rendering in image & text. Build custom UI, not just plain text/value picker.
