diff --git a/src/app/components/generic-select/generic-select.component.html b/src/app/components/generic-select/generic-select.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..58262b7c280cf009a3ccbabd052abebb6e80b3cf
--- /dev/null
+++ b/src/app/components/generic-select/generic-select.component.html
@@ -0,0 +1,8 @@
+<div class="btn-group" dropdown (click)="onSelect($event)">
+    <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
+        {{currentLabel}}
+    </button>
+    <div class="dropdown-menu">
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=entryValue(e)>{{entryLabel(e)}}</a>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/generic-select/generic-select.component.ts b/src/app/components/generic-select/generic-select.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3c0c0b3112b2e48b74bfea3e984dbc168d750004
--- /dev/null
+++ b/src/app/components/generic-select/generic-select.component.ts
@@ -0,0 +1,58 @@
+import { Component, Input, Output, EventEmitter } from "@angular/core";
+
+import { SelectField, } from "../../formulaire/select-field";
+import { SelectEntry } from "../../formulaire/select-entry";
+import { FormulaireService } from "../../services/formulaire/formulaire.service";
+
+/*
+  exemple de template :
+  <div class="btn-group col-12 col-sm-9" dropdown (click)="onSelect($event)">
+    <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
+        {{currentLabel}}
+    </button>
+    <div class="dropdown-menu">
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=e.value>{{e.label}}</a>
+    </div>
+  </div>
+*/
+
+export abstract class GenericSelectComponent {
+    // valeur actuellement sélectionnée
+    // la valeur est le code non affiché repérant une entrée de la liste (cf. [value] dans le templace)
+    private _selectedValue: any;
+
+    /**
+     * selected value event
+     */
+    @Output()
+    private selectChange = new EventEmitter<string>();
+
+    private get currentLabel(): string {
+        if (this._selectedValue != undefined)
+            for (let e of this.entries)
+                if (this.entryValue(e) == this._selectedValue)
+                    return this.entryLabel(e);
+
+        return "<no selection>";
+    }
+
+    private onSelect(event: any) {
+        this._selectedValue = event.target.value;
+        this.selectChange.emit(this._selectedValue);
+    }
+
+    /**
+     * liste des objets sélectionnables
+     */
+    protected abstract get entries(): any[];
+
+    /**
+     * calcule la "valeur" d'une entrée
+     */
+    protected abstract entryValue(entry: any): string;
+
+    /**
+     * calcule l'étiquette d'une entrée (ce qui est affiché dans la liste déroulante)
+     */
+    protected abstract entryLabel(entry: any): string;
+}