diff --git a/src/frontend/plugins/select-search/select-search.component.html b/src/frontend/plugins/select-search/select-search.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..d3336b3241004622063b19b3b7634312c017cffc
--- /dev/null
+++ b/src/frontend/plugins/select-search/select-search.component.html
@@ -0,0 +1,24 @@
+<mat-form-field class="input-form" floatLabel="never">
+  <mat-select [formControl]="formControlSelect" [placeholder]="placeholderLabel" #test>
+    <input *ngIf="datas.length > 5" matInput class="mat-select-search-input mat-select-search-hidden" />
+
+    <div *ngIf="datas.length > 5" class="mat-select-search-inner" [ngClass]="{'mat-select-search-inner-multiple': matSelect.multiple}">
+      <input matInput id="searchSelectInput" [formControl]="formControlSearch" class="mat-select-search-input" #searchSelectInput (keydown)="_handleKeydown($event)"
+        (input)="onInputChange($event.target.value)" (blur)="onBlur($event.target.value)"
+        [placeholder]="lang.filterBy" />
+      <button mat-button *ngIf="formControlSearch.value" mat-icon-button aria-label="Clear" (click)="_reset(true)"
+        class="mat-select-search-clear">
+        <mat-icon class="fa fa-times"></mat-icon>
+      </button>
+    </div>
+
+    <div *ngIf="noEntriesFoundLabel && value && _options?.length === 0 && datas.length > 5" class="mat-select-search-no-entries-found">
+      {{lang.noResult}}
+    </div>
+    <mat-option *ngIf="adminMode"></mat-option>
+    <mat-option *ngFor="let value of filteredDatas | async" [value]="value.id"
+      [title]="value.title !== undefined ? value.title : value.label" [disabled]="value.disabled"
+      [class.opt-group]="value.isTitle" [style.color]="value.color" [innerHTML]="value.label">
+    </mat-option>
+  </mat-select>
+</mat-form-field>
\ No newline at end of file
diff --git a/src/frontend/plugins/select-search/select-search.component.scss b/src/frontend/plugins/select-search/select-search.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7fdc6f47a75ad1989552b15e6a47ef39da74d6b0
--- /dev/null
+++ b/src/frontend/plugins/select-search/select-search.component.scss
@@ -0,0 +1,48 @@
+@import '../../css/vars.scss';
+
+
+$mat-menu-side-padding: 16px !default;
+$scrollbar-width: 17px;
+$clear-button-width: 20px;
+$multiple-check-width: 33px;
+
+.mat-select-search-hidden {
+  visibility: hidden;
+}
+.mat-select-search-inner {
+  position: absolute;
+  top: 0;
+  width: calc(100% + #{2 * $mat-menu-side-padding - $scrollbar-width});
+  border-bottom: 1px solid #cccccc;
+  background: white;
+  z-index: 100;
+  &.mat-select-search-inner-multiple {
+
+    width: calc(100% + #{2 * $mat-menu-side-padding - $scrollbar-width + $multiple-check-width});
+  }
+}
+
+::ng-deep.mat-select-search-panel {
+  /* allow absolute positioning relative to outer options container */
+  transform: none !important;
+  max-height: 350px;
+}
+
+.mat-select-search-input {
+  padding: $mat-menu-side-padding;
+  padding-right: $mat-menu-side-padding + $clear-button-width;
+  box-sizing: border-box;
+
+}
+.mat-select-search-no-entries-found {
+  padding: $mat-menu-side-padding;
+}
+.mat-select-search-clear {
+  position: absolute;
+  right: 0;
+  top: 4px;
+}
+::ng-deep.cdk-overlay-pane-select-search {
+  /* correct offsetY so that the selected option is at the position of the select box when opening */
+  margin-top: -50px;
+}
diff --git a/src/frontend/plugins/select-search/select-search.component.ts b/src/frontend/plugins/select-search/select-search.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..81c3ba7aff2bdd57f1992182660b57eb91fb420e
--- /dev/null
+++ b/src/frontend/plugins/select-search/select-search.component.ts
@@ -0,0 +1,314 @@
+import {
+    AfterViewInit, ChangeDetectorRef,
+    Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, QueryList,
+    ViewChild,
+    Renderer2
+} from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl } from '@angular/forms';
+import { MatOption, MatSelect } from '@angular/material';
+import { take, takeUntil, startWith, map } from 'rxjs/operators';
+import { Subject, ReplaySubject, Observable } from 'rxjs';
+import { LatinisePipe } from 'ngx-pipes';
+import { LANG } from '../../app/translate.component';
+
+@Component({
+    selector: 'plugin-select-search',
+    templateUrl: 'select-search.component.html',
+    styleUrls: ['select-search.component.scss', '../../app/indexation/indexing-form/indexing-form.component.scss']
+})
+export class PluginSelectSearchComponent implements OnInit, OnDestroy, AfterViewInit, ControlValueAccessor {
+    lang: any = LANG;
+    /** Label of the search placeholder */
+    @Input() placeholderLabel = this.lang.chooseValue;
+
+    /** Label to be shown when no entries are found. Set to null if no message should be shown. */
+    @Input() noEntriesFoundLabel = 'Aucun résultat';
+
+    @Input('formControlSelect') formControlSelect: FormControl;
+
+    @Input('datas') datas: any;
+
+
+    /** Reference to the search input field */
+    @ViewChild('searchSelectInput', { read: ElementRef, static: true }) searchSelectInput: ElementRef;
+
+    @ViewChild('test', { static: true }) matSelect: MatSelect;
+
+    /** Current search value */
+    get value(): string {
+        return this._value;
+    }
+    private _value: string;
+
+    onChange: Function = (_: any) => { };
+    onTouched: Function = (_: any) => { };
+
+    public filteredDatas: Observable<string[]>;
+
+    public filteredDatasMulti: ReplaySubject<any[]> = new ReplaySubject<any[]>(1);
+
+    /** Reference to the MatSelect options */
+    public _options: QueryList<MatOption>;
+
+    /** Previously selected values when using <mat-select [multiple]="true">*/
+    private previousSelectedValues: any[];
+
+    /** Whether the backdrop class has been set */
+    private overlayClassSet = false;
+
+    /** Event that emits when the current value changes */
+    private change = new EventEmitter<string>();
+
+    /** Subject that emits when the component has been destroyed. */
+    private _onDestroy = new Subject<void>();
+
+    formControlSearch = new FormControl();
+
+
+    constructor(private latinisePipe: LatinisePipe, private changeDetectorRef: ChangeDetectorRef, private renderer: Renderer2) {
+
+
+    }
+
+    ngOnInit() {
+        // set custom panel class
+        const panelClass = 'mat-select-search-panel';
+        if (this.matSelect.panelClass) {
+            if (Array.isArray(this.matSelect.panelClass)) {
+                this.matSelect.panelClass.push(panelClass);
+            } else if (typeof this.matSelect.panelClass === 'string') {
+                this.matSelect.panelClass = [this.matSelect.panelClass, panelClass];
+            } else if (typeof this.matSelect.panelClass === 'object') {
+                this.matSelect.panelClass[panelClass] = true;
+            }
+        } else {
+            this.matSelect.panelClass = panelClass;
+        }
+
+        // when the select dropdown panel is opened or closed
+        this.matSelect.openedChange
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe((opened) => {
+                if (opened) {
+                    // focus the search field when opening
+                    this._focus();
+                } else {
+                    // clear it when closing
+                    //this._reset();
+                    this.formControlSearch.reset();
+                }
+            });
+
+        // set the first item active after the options changed
+        this.matSelect.openedChange
+            .pipe(take(1))
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe(() => {
+                this._options = this.matSelect.options;
+                this._options.changes
+                    .pipe(takeUntil(this._onDestroy))
+                    .subscribe(() => {
+                        const keyManager = this.matSelect._keyManager;
+                        if (keyManager && this.matSelect.panelOpen) {
+                            // avoid "expression has been changed" error
+                            setTimeout(() => {
+                                keyManager.setFirstItemActive();
+                            });
+                        }
+                    });
+            });
+
+        // detect changes when the input changes
+        /*this.change
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe(() => {
+                this.changeDetectorRef.detectChanges();
+            });*/
+
+
+        setTimeout(() => {
+            this.filteredDatas = this.formControlSearch.valueChanges
+                .pipe(
+                    startWith(''),
+                    map(value => this._filter(value))
+                );
+        }, 800);
+
+
+        // this.initMultipleHandling();
+
+        // load the initial bank list
+
+        //this.filteredDatas.next(this.datas.slice());
+
+        //this.filteredDatasMulti.next(this.datas.slice());
+
+        // listen for search field value changes
+        /*this.formControlSelect.valueChanges
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe(() => {
+                this.filterDatas();
+            });*/
+        /*this.formControlSelect.valueChanges
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe(() => {
+                this.filterDatasMulti();
+            });*/
+    }
+
+    ngOnDestroy() {
+        this._onDestroy.next();
+        this._onDestroy.complete();
+    }
+
+    ngAfterViewInit() {
+        if (this.datas.length > 5) {
+            this.setOverlayClass();
+        }
+    }
+
+    /**
+     * Handles the key down event with MatSelect.
+     * Allows e.g. selecting with enter key, navigation with arrow keys, etc.
+     * @param {KeyboardEvent} event
+     * @private
+     */
+    _handleKeydown(event: KeyboardEvent) {
+        if (event.keyCode === 32) {
+            // do not propagate spaces to MatSelect, as this would select the currently active option
+            event.stopPropagation();
+        }
+
+    }
+
+
+    writeValue(value: string) {
+        const valueChanged = value !== this._value;
+        if (valueChanged) {
+            this._value = value;
+            this.change.emit(value);
+        }
+    }
+
+    onInputChange(value: any) {
+        const valueChanged = value !== this._value;
+        if (valueChanged) {
+            this._value = value;
+            this.onChange(value);
+            this.change.emit(value);
+        }
+    }
+
+    onBlur(value: string) {
+        this.writeValue(value);
+        this.onTouched();
+    }
+
+    registerOnChange(fn: Function) {
+        this.onChange = fn;
+    }
+
+    registerOnTouched(fn: Function) {
+        this.onTouched = fn;
+    }
+
+    /**
+     * Focuses the search input field
+     * @private
+     */
+    public _focus() {
+        // save and restore scrollTop of panel, since it will be reset by focus()
+        // note: this is hacky
+        const panel = this.matSelect.panel.nativeElement;
+        const scrollTop = panel.scrollTop;
+
+        // focus
+        if (this.datas.length > 5) {
+            this.renderer.selectRootElement('#searchSelectInput').focus();
+        }
+        panel.scrollTop = scrollTop;
+    }
+
+    /**
+     * Resets the current search value
+     * @param {boolean} focus whether to focus after resetting
+     * @private
+     */
+    public _reset(focus?: boolean) {
+
+        this.formControlSearch.reset();
+
+        this.renderer.selectRootElement('#searchSelectInput').focus();
+
+    }
+
+    /**
+     * Sets the overlay class  to correct offsetY
+     * so that the selected option is at the position of the select box when opening
+     */
+    private setOverlayClass() {
+        if (this.overlayClassSet) {
+            return;
+        }
+        const overlayClass = 'cdk-overlay-pane-select-search';
+
+        this.matSelect.overlayDir.attach
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe(() => {
+                // note: this is hacky, but currently there is no better way to do this
+                this.searchSelectInput.nativeElement.parentElement.parentElement
+                    .parentElement.parentElement.parentElement.classList.add(overlayClass);
+            });
+
+        this.overlayClassSet = true;
+    }
+
+
+    /**
+     * Initializes handling <mat-select [multiple]="true">
+     * Note: to improve this code, mat-select should be extended to allow disabling resetting the selection while filtering.
+     */
+    private initMultipleHandling() {
+        // if <mat-select [multiple]="true">
+        // store previously selected values and restore them when they are deselected
+        // because the option is not available while we are currently filtering
+        this.matSelect.valueChange
+            .pipe(takeUntil(this._onDestroy))
+            .subscribe((values) => {
+                if (this.matSelect.multiple) {
+                    let restoreSelectedValues = false;
+                    if (this._value && this._value.length
+                        && this.previousSelectedValues && Array.isArray(this.previousSelectedValues)) {
+                        if (!values || !Array.isArray(values)) {
+                            values = [];
+                        }
+                        const optionValues = this.matSelect.options.map(option => option.value);
+                        this.previousSelectedValues.forEach(previousValue => {
+                            if (values.indexOf(previousValue) === -1 && optionValues.indexOf(previousValue) === -1) {
+                                // if a value that was selected before is deselected and not found in the options, it was deselected
+                                // due to the filtering, so we restore it.
+                                values.push(previousValue);
+                                restoreSelectedValues = true;
+                            }
+                        });
+                    }
+
+                    if (restoreSelectedValues) {
+                        this.matSelect._onChange(values);
+                    }
+
+                    this.previousSelectedValues = values;
+                }
+            });
+    }
+
+    private _filter(value: string): string[] {
+        if (typeof value === 'string') {
+            const filterValue = this.latinisePipe.transform(value.toLowerCase());
+            return this.datas.filter((option: any) => this.latinisePipe.transform(option['label'].toLowerCase()).includes(filterValue));
+        } else {
+            return this.datas;
+        }
+    }
+
+}