Create a Custom Input for Ion-Select

Build something unique that fits your app

Sergey Rudenko
Dec 14, 2019 · 4 min read
Custom ion-select input

This article covers a way to implement a custom input field for the ‘ion-select’ component in the Ionic 4/Angular 8 application, which by default does not allow editing of the options in it.

<ion-label>Hair Color</ion-label>
<ion-select-option selected>Custom</ion-select-option>

The ion-select component above allows selecting one option out of three available in the Ionic 4 application. There is a use case where we want a user to be able to actually type in the option that they want. We are going to achieve that smooth UX journey by supplementing the ion-select flow with AlertController.

Let’s first cover some things that will help us structure our approach and define our scope:

  1. First, allowing users to add their custom values means we should support n-amount of <ion-select-options> in our template, so we have to use *ngFor directive and store the current set of values in our class (ts file).
  2. We should ensure that all the changes a user is making are picked up by Angular and are duly rendered in the template (we will see what that means in the alert controller modal handling).
  3. We should account for a fallback scenario in case a user-selected ‘Custom’ option but then canceled the creation of a new option.
  4. Finally, we should understand the constraint that we will not be able to provide a “delete” custom option functionality in this scope. Should we need to allow it, we probably will require another UI widget to handle such a scenario, so this will be out of the scope of this article.

Step 1: Start a new Ionic 4 template and modify your

import { Component } from '@angular/core'; 
import { AlertController } from '@ionic/angular';
selector: 'app-home',
templateUrl: ''
export class HomePage { public colors: Array<string>; public currentColor: string; constructor(public alertController: AlertController) {} ngOnInit() {
this.colors = ["Custom", "Brown", "Dark"];
this.currentColor = "Brown";

Here we are importing AlertController and injecting it via the constructor, then declaring two properties and their types: colors and currentColor.

Then, inside onInit hook, we assign initial values for these properties.

Step 2: We add ion-select, add replication via *ngFor and add all necessary bindings inside

<ion-toolbar color="primary">
Ion-select with custom input
<ion-content padding><ion-item>
<ion-label>Hair Color</ion-label>
<ion-select #mySelect [value]="currentColor" [selectedText]="currentColor" (ionChange)="selectChanged(mySelect.value)">
<ion-select-option *ngFor="let color of colors" [selected]="color === currentColor">{{ color }}</ion-select-option>

Some highlights:

  • We bind both ‘value’ and ‘selectedText’ properties to the same currentColor property to ensure we have consistency between what is rendered and what is selected.
  • We add (ionChange) event binding so that we could handle all options changes inside of our
  • Finally, we leverage *ngFor directive to replicate color options using the ‘colors’ array that we have and we bind ‘selected’ property to ensure a user can see which option is chosen already.

Step 3: We implement methods inside to support our use case leveraging AlertController:

  selectChanged(selectedColor) {
if (selectedColor === 'Custom') {
} else {
this.currentColor = selectedColor;

We add ‘selectChanged’ method, which runs on very simple logic:

  • Receive ‘selectedColor’ from our template code.
  • If our user selects ‘Custom’ color — we want to handle further interaction inside another method: inputCustomColorValue().
  • And ‘else’ means we simply update currentColor value and our property bindings inside our template will handle the rest to show user proper new values.

Then, we implement our custom input method:

async inputCustomColorValue() {  const inputAlert = await this.alertController.create({
header: 'Enter your custom color:',
inputs: [ { type: 'text', placeholder: 'type in' } ],
buttons: [ { text: 'Cancel' }, { text: 'Ok' } ]
inputAlert.onDidDismiss((data) => {
let customColorName: string =[0];
if (customColorName) {
let indexFound = this.colors.findIndex(color => color === customColorName)
if (indexFound === -1) {
this.currentColor = customColorName;
} else {
this.currentColor = this.colors[indexFound];
await inputAlert.present();


Here, we are using AlertController to create a simple text input alert, then we handle the result of user interaction inside the onDidDismiss method. Some notes:

  • We use onDidDismiss vs. button handler because we want Angular to pick up the changes in our data. Should these changes happen inside alert controller components — we would have to make extra efforts to update our components bindings (trigger change detection, or explicitly run handler inside Angular zone, etc).
  • We leverage ‘indexFound’ to check if such ‘color’ already exists and we are not adding such color to our ‘colors’ array, but still allowing the user to select it.

That’s it. We’ve fully implemented the functionality we intended to achieve. Here it is:

Better Programming

Advice for programmers.

Sergey Rudenko

Written by

Tech enthusiast, producer (currently Senior Tech Product Manager @ Riot Games), author of something awesome in the future;)

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade