diff --git a/angular.json b/angular.json
index 6ff6ea82bb729a7d47c0e13aad7011ce42e08e2d..5483fa1cd096e150f7febcaae44cb71c0e944afb 100644
--- a/angular.json
+++ b/angular.json
@@ -47,6 +47,10 @@
                 {
                   "replace": "src/i18n/geosource/geosource.ts",
                   "with": "src/i18n/geosource/geosource.fr.ts"
+                },
+                {
+                  "replace": "src/i18n/contact/contact.ts",
+                  "with": "src/i18n/contact/contact.fr.ts"
                 }
               ]
             },
@@ -99,6 +103,10 @@
                 {
                   "replace": "src/i18n/geosource/geosource.ts",
                   "with": "src/i18n/geosource/geosource.fr.ts"
+                },
+                {
+                  "replace": "src/i18n/contact/contact.ts",
+                  "with": "src/i18n/contact/contact.fr.ts"
                 }
               ],
               "outputPath": "dist/fr",
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 06ff11ae21af544d9826869eaf1a5b177e2b1ad6..2c744415a07e4f794f0f01504d281c71ec595631 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -3,10 +3,10 @@ import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
 import { AppRoutes } from './routes';
 
 export const routes: Routes = [
-  {
-    path: AppRoutes.research.uri,
-    loadChildren: './geosource/geosource.module#GeosourceModule',
-  },
+  // {
+  //   path: AppRoutes.research.uri,
+  //   loadChildren: './geosource/geosource.module#GeosourceModule',
+  // },
 ];
 
 @NgModule({
diff --git a/src/app/core/components/contact/contact.component.html b/src/app/core/components/contact/contact.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..c0077ff24fe75fe9e5554692dcce92cfc0662435
--- /dev/null
+++ b/src/app/core/components/contact/contact.component.html
@@ -0,0 +1,188 @@
+<h1 class="has-text-centered" i18n="@@contact.contactUs">Contact us</h1>
+
+<div class="contact-form-container">
+  <h2 i18n="@@contact.contactForm">Form contact</h2>
+
+  <form [formGroup]="form" (ngSubmit)="send()">
+    <div class="columns is-multiline">
+      <div class="column is-12-mobile is-2-tablet is-3-desktop">
+        <h3 i18n="@@contact.identity">Identity</h3>
+      </div>
+
+      <div class="column is-12-mobile is-10-tablet is-9-desktop">
+        <div class="fields-container">
+
+          <div class="field">
+            <label class="label" for="lastname" i18n="@@contact.lastname">Lastname</label>
+            <p class="control has-icons-right">
+              <input id="lastname" class="input" type="text" formControlName="lastname" (keyup)="toUppercase('lastname')"
+                [ngClass]="{'is-danger': fieldIsInvalid('lastname'), 'is-success': fieldIsValid('lastname')}">
+              <span class="icon is-small is-right has-text-success" *ngIf="fieldIsValid('lastname')">
+                <i class="fas fa-check-circle"></i>
+              </span>
+              <span class="icon is-small is-right has-text-danger" *ngIf="fieldIsInvalid('lastname')">
+                <i class="fas fa-exclamation-circle"></i>
+              </span>
+            </p>
+
+            <div class="incorrect-field-message" *ngIf="fieldIsInvalid('lastname')">
+              <div *ngIf="form.controls['lastname'].errors.required" i18n="@@contact.errors.missingLastname">
+                You must indicate a lastname.
+              </div>
+              <div *ngIf="form.controls['lastname'].errors.pattern" i18n="@@contact.errors.forbiddenCharacters">
+                Special characters are forbidden.
+              </div>
+            </div>
+          </div>
+
+          <div class="field">
+            <label class="label" for="firstname" i18n="@@contact.firstname">Firstname</label>
+            <p class="control has-icons-right">
+              <input id="firstname" class="input" type="text" (keyup)="toUppercase('firstname')" formControlName="firstname"
+                [ngClass]="{'is-danger': fieldIsInvalid('firstname'), 'is-success': fieldIsValid('firstname')}">
+              <span class="icon is-small is-right has-text-success" *ngIf="fieldIsValid('firstname')">
+                <i class="fas fa-check-circle"></i>
+              </span>
+              <span class="icon is-small is-right has-text-danger" *ngIf="fieldIsInvalid('firstname')">
+                <i class="fas fa-exclamation-circle"></i>
+              </span>
+            </p>
+
+            <div class="incorrect-field-message" *ngIf="fieldIsInvalid('firstname')">
+              <div *ngIf="form.controls['firstname'].errors.required" i18n="@@contact.errors.missingFirstname">
+                You must indicate a firstname.
+              </div>
+              <div *ngIf="form.controls['lastname'].errors.pattern" i18n="@@contact.errors.forbiddenCharacters">
+                Special characters are forbidden.
+              </div>
+            </div>
+          </div>
+
+          <div class="field">
+            <label class="label" for="email" i18n="@@contact.email">Email</label>
+            <p class="control has-icons-right">
+              <input id="email" class="input" type="email" formControlName="email" [ngClass]="{'is-danger': fieldIsInvalid('email'), 'is-success': fieldIsValid('email')}">
+              <span class="icon is-small is-right has-text-success" *ngIf="fieldIsValid('email')">
+                <i class="fas fa-check-circle"></i>
+              </span>
+              <span class="icon is-small is-right has-text-danger" *ngIf="fieldIsInvalid('email')">
+                <i class="fas fa-exclamation-circle"></i>
+              </span>
+            </p>
+
+            <div class="incorrect-field-message" *ngIf="fieldIsInvalid('email')">
+              <div *ngIf="form.controls['email'].errors.required" i18n="@@contact.errors.missingEmail">
+                You must enter an email address.
+              </div>
+
+              <div *ngIf="form.controls['email'].errors.email" i18n="@@contact.errors.invalidEmail">
+                You must enter a valid email address.
+              </div>
+            </div>
+          </div>
+
+          <div class="field">
+            <label class="label" for="emailConfirmation" i18n="@@contact.emailConfirmation">Confirm your email
+              address</label>
+            <p class="control has-icons-right">
+              <input blockCopyPaste id="emailConfirmation" class="input" type="email" formControlName="emailConfirmation"
+                [ngClass]="{'is-danger': emailConfirmationError || fieldIsInvalid('emailConfirmation'), 'is-success': !emailConfirmationError && fieldIsValid('emailConfirmation')}">
+              <span class="icon is-small is-right has-text-success" *ngIf="!emailConfirmationError && fieldIsValid('emailConfirmation')">
+                <i class="fas fa-check-circle"></i>
+              </span>
+              <span class="icon is-small is-right has-text-danger" *ngIf="emailConfirmationError || fieldIsInvalid('emailConfirmation')">
+                <i class="fas fa-exclamation-circle"></i>
+              </span>
+            </p>
+
+            <div class="incorrect-field-message" *ngIf="fieldIsInvalid('emailConfirmation')">
+              <div *ngIf="form.controls['emailConfirmation'].errors.required" i18n="@@contact.errors.missingConfirmationEmail">
+                You must confirm your email address.
+              </div>
+
+              <div *ngIf="form.controls['emailConfirmation'].errors.email" i18n="@@contact.errors.invalidEmail">
+                You must enter a valid email address.
+              </div>
+            </div>
+            <div class="incorrect-field-message" *ngIf="emailConfirmationError">
+              <div *ngIf="emailConfirmationError" i18n="@@contact.errors.confirmationEmailNotCorresponding">
+                You must enter the same email address.
+              </div>
+            </div>
+          </div>
+
+        </div>
+      </div>
+
+      <div class="column is-12-mobile is-2-tablet is-3-desktop">
+        <h3 i18n="@@contact.message">Message</h3>
+      </div>
+
+      <div class="column is-12-mobile is-10-tablet is-9-desktop">
+        <div class="field">
+          <label class="label" [for]="subjectLabelFor" i18n="@@contact.subject">Subject</label>
+          <div class="dropdown" [ngClass]="{'is-active': subjectDropdownState}" (clickOutside)="closeSubjectDropdown()">
+            <div class="dropdown-trigger" (click)="toggleSubject()">
+              <button id="subjectDropdown" type="button" class="button" aria-haspopup="true" aria-controls="dropdown-menu"
+                [disabled]="formDisabled">
+                <span>{{ selectedSubject !== null && selectedSubject.value !== null ? selectedSubject.value : '---'}}</span>
+                <span class="icon is-small">
+                  <i class="fas fa-angle-down" aria-hidden="true"></i>
+                </span>
+              </button>
+            </div>
+            <div class="dropdown-menu" id="dropdown-menu" role="menu">
+              <ul class="dropdown-content">
+                <li class="dropdown-item" *ngFor="let sub of subjects" (keydown.enter)="setSubject(sub)" (click)="setSubject(sub)"
+                  tabindex=0>
+                  {{ sub.value }}
+                </li>
+              </ul>
+            </div>
+          </div>
+          <p class="control has-icons-right subject-input-control" *ngIf="displaySubjectInput === true">
+            <input id="subjectInput" class="input" type="text" formControlName="subject" [ngClass]="{'is-danger': fieldIsInvalid('subject'), 'is-success': fieldIsValid('subject')}">
+            <span class="icon is-small is-right has-text-success" *ngIf="fieldIsValid('subject')">
+              <i class="fas fa-check-circle"></i>
+            </span>
+            <span class="icon is-small is-right has-text-danger" *ngIf="fieldIsInvalid('subject')">
+              <i class="fas fa-exclamation-circle"></i>
+            </span>
+          </p>
+
+          <div class="incorrect-field-message" *ngIf="fieldIsInvalid('subject')">
+            <div *ngIf="form.controls['subject'].errors.required" i18n="@@contact.errors.missingSubject">
+              You must enter a subject.
+            </div>
+          </div>
+        </div>
+
+        <div class="field">
+          <label class="label" for="text" i18n="@@contact.messageField">Message</label>
+          <p class="control has-icons-right">
+            <textarea id="text" class="textarea has-fixed-size" type="textarea" formControlName="text" [ngClass]="{'is-danger': fieldIsInvalid('text'), 'is-success': fieldIsValid('text')}"
+              rows=6></textarea>
+            <span class="icon is-small is-right has-text-success" *ngIf="fieldIsValid('text')">
+              <i class="fas fa-check-circle"></i>
+            </span>
+            <span class="icon is-small is-right has-text-danger" *ngIf="fieldIsInvalid('text')">
+              <i class="fas fa-exclamation-circle"></i>
+            </span>
+          </p>
+
+          <div class="incorrect-field-message" *ngIf="fieldIsInvalid('text')">
+            <div *ngIf="form.controls['text'].errors.required" i18n="@@contact.errors.invalidMessage">
+              You must enter a message.
+            </div>
+          </div>
+        </div>
+
+        <div class="has-text-right button-wrapper">
+          <button class="button button-gl is-outlined" type="button" [disabled]="formDisabled" (click)="cancel()" i18n="@@contact.cancel">Cancel</button>
+          <button type="submit" class="button button-gl" [ngClass]="{'is-loading': formDisabled}" [disabled]="formIsInvalid || formDisabled"
+            i18n="@@contact.send">Send</button>
+        </div>
+      </div>
+    </div>
+  </form>
+</div>
\ No newline at end of file
diff --git a/src/app/core/components/contact/contact.component.scss b/src/app/core/components/contact/contact.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..5b76c9a460dd64dedc83164f35c6b107013d95be
--- /dev/null
+++ b/src/app/core/components/contact/contact.component.scss
@@ -0,0 +1,74 @@
+@import '../../../../scss/variables.scss';
+@import "../../../../../node_modules/bulma/sass/utilities/_all";
+
+h1 {
+  font-size: 2rem;
+  margin: 0;
+  padding: 1.25rem;
+  background-color: white;
+}
+
+h2 {
+  font-size: 1.6rem;
+  margin-bottom: 2rem;
+}
+
+h3 {
+  margin-top: 0;
+  margin-bottom: 0;
+  margin-right: 0;
+}
+
+.contact-form-container {  
+  background-color: white;
+  padding: 0 1rem 0 1rem;
+  margin-left: 1.5rem;
+  margin-right: 1.5rem;
+  margin-bottom: 1.25rem;
+
+  
+  @media(min-width: $tablet) {
+    .fields-container {
+      width: 66%;
+    }  
+  }
+
+  label {
+    font-size: 1rem;
+    font-weight: normal;
+    font-style: normal;
+    &:hover {
+      cursor: pointer;
+    }
+  }
+
+  .incorrect-field-message {
+    color: #333745;
+    font-style: italic;
+    font-size: $size-6;
+  }
+
+  .subject-input-control {
+    margin-top: 0.5rem;
+  }
+
+  .dropdown-item:hover {
+    cursor: pointer;
+    background-color: lightgrey;
+  }
+
+  .button-gl {
+    width:8rem;
+
+    &:first-of-type {
+      margin-right: 1.25rem;
+    }
+  }
+}
+
+.title-label.is-danger {
+  &:hover, &:focus {
+    background-color:white;
+    color: $red;
+  }
+}
\ No newline at end of file
diff --git a/src/app/core/components/contact/contact.component.spec.ts b/src/app/core/components/contact/contact.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c96cc896011afa63744b689c3eba64c88c058b0f
--- /dev/null
+++ b/src/app/core/components/contact/contact.component.spec.ts
@@ -0,0 +1,400 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ContactComponent } from './contact.component';
+import { ReactiveFormsModule, FormControl, AbstractControl } from '@angular/forms';
+import { EmailService, NotificationService, NavigationHistoryService } from '../../services';
+import { BehaviorSubject, of } from 'rxjs';
+import { Email } from '../../models';
+import { RouterTestingModule } from '@angular/router/testing';
+
+export class NotificationServiceMock {
+
+  constructor() { }
+
+  send(email: Email) {
+    return of(null);
+  }
+
+}
+
+export class EmailServiceMock {
+
+  _notification: BehaviorSubject<Notification> = new BehaviorSubject(null);
+
+  constructor() { }
+
+  notify(notification: Notification) {
+    this._notification.next(notification);
+  }
+
+  get notification$() {
+    return this._notification;
+  }
+
+}
+
+describe('ContactComponent', () => {
+  let component: ContactComponent;
+  let fixture: ComponentFixture<ContactComponent>;
+  let firstname: AbstractControl;
+  let lastname: AbstractControl;
+  let email: AbstractControl;
+  let emailConfirmation: AbstractControl;
+  let subject: AbstractControl;
+  let text: AbstractControl;
+
+  describe('Template', () => {
+    beforeEach(async(() => {
+      TestBed.configureTestingModule({
+        imports: [
+          ReactiveFormsModule,
+          RouterTestingModule,
+        ],
+        providers: [
+          {
+            provide: EmailService,
+            useClass: EmailServiceMock,
+          },
+          {
+            provide: NotificationService,
+            useClass: NotificationServiceMock,
+          },
+          NavigationHistoryService,
+        ],
+        declarations: [ContactComponent],
+      })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+      fixture = TestBed.createComponent(ContactComponent);
+      component = fixture.componentInstance;
+      fixture.detectChanges();
+      firstname = component.form.controls.firstname;
+      lastname = component.form.controls.lastname;
+      email = component.form.controls.email;
+      emailConfirmation = component.form.controls.emailConfirmation;
+      subject = component.form.controls.subject;
+      text = component.form.controls.text;
+    });
+
+    it('should create', () => {
+      expect(component).toBeTruthy();
+    });
+
+    describe('Form validation', () => {
+
+      it('form invalid when empty', () => {
+        expect(component.form.valid).toBeFalsy();
+      });
+
+      describe('Firstname control validation', () => {
+        beforeEach(() => {
+          firstname.reset();
+        });
+
+        it('firstname control is valid with lowercase and uppercase letter', () => {
+          // Given
+          const value = 'John Doe';
+          // When
+          firstname.setValue(value);
+          // Then
+          expect(firstname.valid).toBeTruthy();
+        });
+
+        it('firstname control is valid with letter and space', () => {
+          // Given
+          const value = 'John Doe';
+          // When
+          firstname.setValue(value);
+          // Then
+          expect(firstname.valid).toBeTruthy();
+        });
+
+        it('firstname control is valid with letter and dash', () => {
+          // Given
+          const value = 'Jean-jacques';
+          // When
+          firstname.setValue(value);
+          // Then
+          expect(firstname.valid).toBeTruthy();
+        });
+
+        it('firstname control is valid with letter and apostrophe', () => {
+          // Given
+          const value = 'De\'Andre';
+          // When
+          firstname.setValue(value);
+          // Then
+          expect(firstname.valid).toBeTruthy();
+        });
+
+        it('firstname control accept any of those characters', () => {
+          // Given
+          let specialChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+          specialChars += 'abcdefghijklmnopqrstuvwxyz';
+          specialChars += 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝ';
+          specialChars += 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ';
+          // When
+          firstname.setValue(specialChars);
+          // Then
+          expect(firstname.valid).toBeTruthy();
+        });
+
+        it('firstname control is invalid if first letter is lowercased, has error "pattern"', () => {
+          // Given
+          const value = 'david';
+          // When
+          firstname.setValue(value);
+          const errors = firstname.errors || {};
+          // Then
+          expect(firstname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('firstname control is invalid if contains numbers', () => {
+          // Given
+          const value = '0123456789';
+          // When
+          firstname.setValue(value);
+          const errors = firstname.errors || {};
+          // Then
+          expect(firstname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('firstname control is invalid if contains special characters', () => {
+          // Given
+          const value = '"*$^!qjsdk+°)';
+          // When
+          firstname.setValue(value);
+          const errors = firstname.errors || {};
+          // Then
+          expect(firstname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('firstname control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          firstname.setValue(value);
+          const errors = firstname.errors || {};
+          // Then
+          expect(firstname.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+      });
+
+      describe('Lastname control validation', () => {
+        beforeEach(() => {
+          lastname.reset();
+        });
+
+        it('lastname control is valid with lowercase and uppercase letter', () => {
+          // Given
+          const value = 'John Doe';
+          // When
+          lastname.setValue(value);
+          // Then
+          expect(lastname.valid).toBeTruthy();
+        });
+
+        it('lastname control is valid with letter and space', () => {
+          // Given
+          const value = 'John Doe';
+          // When
+          lastname.setValue(value);
+          // Then
+          expect(lastname.valid).toBeTruthy();
+        });
+
+        it('lastname control is valid with letter and dash', () => {
+          // Given
+          const value = 'Jean-jacques';
+          // When
+          lastname.setValue(value);
+          // Then
+          expect(lastname.valid).toBeTruthy();
+        });
+
+        it('lastname control is valid with letter and apostrophe', () => {
+          // Given
+          const value = 'De\'Andre';
+          // When
+          lastname.setValue(value);
+          // Then
+          expect(lastname.valid).toBeTruthy();
+        });
+
+        it('lastname control accept any of those characters', () => {
+          // Given
+          let specialChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+          specialChars += 'abcdefghijklmnopqrstuvwxyz';
+          specialChars += 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝ';
+          specialChars += 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ';
+          // When
+          lastname.setValue(specialChars);
+          // Then
+          expect(lastname.valid).toBeTruthy();
+        });
+
+        it('lastname control is invalid if first letter is lowercased, has error "pattern"', () => {
+          // Given
+          const value = 'david';
+          // When
+          lastname.setValue(value);
+          const errors = lastname.errors || {};
+          // Then
+          expect(lastname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('lastname control is invalid if contains numbers', () => {
+          // Given
+          const value = '0123456789';
+          // When
+          lastname.setValue(value);
+          const errors = lastname.errors || {};
+          // Then
+          expect(lastname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('lastname control is invalid if contains special characters', () => {
+          // Given
+          const value = '"*$^!qjsdk+°)';
+          // When
+          lastname.setValue(value);
+          const errors = lastname.errors || {};
+          // Then
+          expect(lastname.valid).toBeFalsy();
+          expect(errors['pattern']).toBeTruthy();
+        });
+
+        it('lastname control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          lastname.setValue(value);
+          const errors = lastname.errors || {};
+          // Then
+          expect(lastname.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+      });
+
+      describe('Email control validation', () => {
+        beforeEach(() => {
+          email.reset();
+        });
+
+        it('Email control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          email.setValue(value);
+          const errors = email.errors || {};
+          // Then
+          expect(email.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+
+        it('Email control is invalid if the value is not a valid email', () => {
+          // Given
+          const value = 'toto.grandlyon.com';
+          // When
+          email.setValue(value);
+          const errors = email.errors || {};
+          // Then
+          expect(email.valid).toBeFalsy();
+          expect(errors['email']).toBeTruthy();
+        });
+
+        it('Email control is valid if the value is a valid email', () => {
+          // Given
+          const value = 'toto@grandlyon.com';
+          // When
+          email.setValue(value);
+          const errors = email.errors || {};
+          // Then
+          expect(email.valid).toBeTruthy();
+          expect(errors).toEqual({});
+        });
+      });
+
+      describe('emailConfirmation control validation', () => {
+        beforeEach(() => {
+          emailConfirmation.reset();
+        });
+
+        it('emailConfirmation control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          emailConfirmation.setValue(value);
+          const errors = emailConfirmation.errors || {};
+          // Then
+          expect(emailConfirmation.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+
+        it('emailConfirmation control is invalid if the value is not a valid emailConfirmation', () => {
+          // Given
+          const value = 'toto.grandlyon.com';
+          // When
+          emailConfirmation.setValue(value);
+          const errors = emailConfirmation.errors || {};
+          // Then
+          expect(emailConfirmation.valid).toBeFalsy();
+          expect(errors['email']).toBeTruthy();
+        });
+
+        it('emailConfirmation control is valid if the value is a valid emailConfirmation', () => {
+          // Given
+          const value = 'toto@grandlyon.com';
+          // When
+          emailConfirmation.setValue(value);
+          const errors = emailConfirmation.errors || {};
+          // Then
+          expect(emailConfirmation.valid).toBeTruthy();
+          expect(errors).toEqual({});
+        });
+      });
+
+      describe('subject control validation', () => {
+        beforeEach(() => {
+          subject.reset();
+        });
+
+        it('subject control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          subject.setValue(value);
+          const errors = subject.errors || {};
+          // Then
+          expect(subject.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+      });
+
+      describe('text control validation', () => {
+        beforeEach(() => {
+          text.reset();
+        });
+
+        it('text control is invalid if the value is empty', () => {
+          // Given
+          const value = '';
+          // When
+          text.setValue(value);
+          const errors = text.errors || {};
+          // Then
+          expect(text.valid).toBeFalsy();
+          expect(errors['required']).toBeTruthy();
+        });
+      });
+    });
+  });
+});
diff --git a/src/app/core/components/contact/contact.component.ts b/src/app/core/components/contact/contact.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e06099f82cabc4b6c1b0e82bd188d7004f70664e
--- /dev/null
+++ b/src/app/core/components/contact/contact.component.ts
@@ -0,0 +1,166 @@
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
+import { EmailService, NotificationService, NavigationHistoryService } from '../../services';
+import { Email } from '../../models';
+import { subjects as Subjects, feedbackMessages } from '../../../../i18n/contact/contact';
+import { Router, ActivatedRoute } from '@angular/router';
+import { AppRoutes } from '../../../routes';
+
+@Component({
+  selector: 'app-contact',
+  templateUrl: './contact.component.html',
+  styleUrls: ['./contact.component.scss'],
+})
+export class ContactComponent implements OnInit {
+
+  form: FormGroup;
+  subjectDropdownState = false;
+  subjects: Subject[] = Subjects; // Keep this line in order to access the subjects in the html template
+  selectedSubject: Subject = null;
+
+  constructor(
+    private _fb: FormBuilder,
+    private _emailService: EmailService,
+    private _notificationService: NotificationService,
+    private _navigationHistoryService: NavigationHistoryService,
+    private _router: Router,
+    private _route: ActivatedRoute,
+  ) {
+    this.form = this._fb.group(
+      {
+        firstname: ['', [
+          Validators.required,
+          Validators.pattern('([A-ZÀ-ÖØ-Ý][a-zà-öø-ýÿA-ZÀ-ÖØ-Ý]*)([ \'-][a-zA-ZÀ-ÖØ-öø-ýÿ]*)*'),
+        ]],
+        lastname: ['', [Validators.required,
+          Validators.pattern('([A-ZÀ-ÖØ-Ý][a-zà-öø-ýÿA-ZÀ-ÖØ-Ý]*)([ \'-][a-zA-ZÀ-ÖØ-öø-ýÿ]*)*'),
+        ]],
+        email: ['', [Validators.required, Validators.email]],
+        emailConfirmation: ['', [Validators.required, Validators.email]],
+        subject: ['', Validators.required],
+        text: ['', Validators.required],
+      });
+  }
+
+  ngOnInit() {
+    this._route.queryParams.subscribe((params) => {
+      if (params.subject) {
+        this.selectedSubject = this.subjects.find(sub => sub.key === 'other');
+        this.form.controls.subject.patchValue(params.subject);
+      } else {
+        this.selectedSubject = null;
+      }
+    });
+  }
+
+  send() {
+    if (!this.formIsInvalid) {
+      const email = new Email(this.form.value);
+      this.form.disable();
+      this._emailService.send(email).subscribe(
+        (res) => {
+          this.form.enable();
+          this._notificationService.notify(
+            {
+              type: 'success',
+              message: feedbackMessages.success,
+            },
+          );
+          this.form.reset();
+        },
+        (err) => {
+          this.form.enable();
+          this._notificationService.notify(
+            {
+              type: 'error',
+              message: feedbackMessages.error,
+            },
+          );
+        },
+      );
+    }
+  }
+
+  get emailConfirmationIsCorrect(): boolean {
+    const value = this.form.controls.email.value === this.form.controls.emailConfirmation.value ? true : false;
+    return value;
+  }
+
+  get emailConfirmationError() {
+    // Display the message if
+    // Input values have been modified
+    // Input values have been modified but the email values are not similar
+    return this.form.controls['email'].touched &&
+      this.form.controls['emailConfirmation'].touched &&
+      !this.emailConfirmationIsCorrect;
+  }
+
+  // Return true if one of the fields at least doesn't respect its validators
+  // or if the confirmation email is different from the email
+  get formIsInvalid() {
+    const controls = this.form.controls;
+    const value = this.form.invalid || this.emailConfirmationError;
+    return value;
+  }
+
+  fieldIsInvalid(field: string) {
+    return (this.form.controls[field].touched) && this.form.controls[field].invalid;
+  }
+
+  fieldIsValid(field: string) {
+    return (this.form.controls[field].touched) && this.form.controls[field].valid;
+  }
+
+  toggleSubject() {
+    if (!this.formDisabled) {
+      this.subjectDropdownState = !this.subjectDropdownState;
+    }
+  }
+
+  closeSubjectDropdown() {
+    this.subjectDropdownState = false;
+  }
+
+  setSubject(subject: Subject) {
+    this.toggleSubject();
+    this.selectedSubject = subject;
+    if (this.selectedSubject.key === 'other') {
+      this.form.controls.subject.patchValue('');
+      this.form.controls.subject.reset();
+    } else {
+      this.form.controls.subject.patchValue(this.selectedSubject.value);
+    }
+  }
+
+  cancel() {
+    const previous = this._navigationHistoryService.getFromLast(1);
+    if (previous !== null) {
+      this._router.navigateByUrl(previous);
+    } else {
+      this._router.navigateByUrl(AppRoutes.home.uri);
+    }
+  }
+
+  get subjectLabelFor(): string {
+    return this.displaySubjectInput ? 'subjectInput' : 'subjectDropdown';
+  }
+
+  get formDisabled(): boolean {
+    return this.form.disabled;
+  }
+
+  get displaySubjectInput(): boolean {
+    return (this.selectedSubject && this.selectedSubject.key) === 'other' ? true : false;
+  }
+
+  toUppercase(controlName: string) {
+    const input = this.form.controls[controlName].value;
+    const uppercased = input.substring(0, 1).toUpperCase() + input.substring(1);
+    this.form.controls[controlName].patchValue(uppercased);
+  }
+}
+
+interface Subject {
+  key: string;
+  value: string;
+}
diff --git a/src/app/core/components/footer/footer.component.html b/src/app/core/components/footer/footer.component.html
index a19ff64f6f047d33ec4ec4e6573559bcd66dbc5a..a86ecc5c4c290cd113084eb5c6de29751d9e4cbf 100644
--- a/src/app/core/components/footer/footer.component.html
+++ b/src/app/core/components/footer/footer.component.html
@@ -34,7 +34,7 @@
               <a class="legal-mentions-link" [routerLink]="['/', AppRoutes.legalNotices.uri]"  i18n="@@footer.notices">Legal Notices</a>
             </li>
             <li class="left-border">
-              <a routerLink="/" i18n="@@footer.contactus">Contact Us</a>
+              <a [routerLink]="['/', AppRoutes.contact.uri]" i18n="@@footer.contactus">Contact Us</a>
             </li>
           </ul>
         </div>
diff --git a/src/app/core/components/index.ts b/src/app/core/components/index.ts
index 82c8d51d679ad7dbfaa2a3ab26af313913aafd4c..84499c9c375311044cafe141314ed1f4dfd6555e 100644
--- a/src/app/core/components/index.ts
+++ b/src/app/core/components/index.ts
@@ -3,8 +3,9 @@ import { MainComponent } from './main/main.component';
 import { FooterComponent } from './footer/footer.component';
 import { NotificationsComponent } from './notifications/notifications.component';
 import { ErrorComponent } from './error/error.component';
+import { ContactComponent } from './contact/contact.component';
 
-export { HeaderComponent, MainComponent, FooterComponent, NotificationsComponent, ErrorComponent };
+export { HeaderComponent, MainComponent, FooterComponent, NotificationsComponent, ErrorComponent, ContactComponent };
 
 // tslint:disable-next-line:variable-name
 export const CoreComponents = [
@@ -13,4 +14,5 @@ export const CoreComponents = [
   FooterComponent,
   NotificationsComponent,
   ErrorComponent,
+  ContactComponent,
 ];
diff --git a/src/app/core/core-routing.module.ts b/src/app/core/core-routing.module.ts
index 5f7c40380de53928ca3c06c5c803c518ac7fb50a..8b73098a4c181c67f2d96e2304ea3bda276835c7 100644
--- a/src/app/core/core-routing.module.ts
+++ b/src/app/core/core-routing.module.ts
@@ -1,7 +1,7 @@
 import { NgModule } from '@angular/core';
 import { Routes, RouterModule } from '@angular/router';
 import { AppRoutes } from '../routes';
-import { ErrorComponent } from './components';
+import { ErrorComponent, ContactComponent } from './components';
 
 export const routes: Routes = [
   {
@@ -16,6 +16,13 @@ export const routes: Routes = [
       title: AppRoutes.error.title,
     },
   },
+  {
+    path: AppRoutes.contact.uri,
+    component: ContactComponent,
+    data: {
+      title: AppRoutes.contact.title,
+    },
+  },
 ];
 
 @NgModule({
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 4a5b5aa6c31e21248953c02735e6b3a45742a71b..058450e9b4b9cf934c204c381d8c6a216fae33e7 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -9,12 +9,14 @@ import { HttpErrorResponseInterceptor } from './interceptors/http-error-response
 import { HTTP_INTERCEPTORS } from '@angular/common/http';
 import { CoreServices } from './services';
 import { RouterModule } from '../../../node_modules/@angular/router';
+import { ReactiveFormsModule } from '@angular/forms';
 
 @NgModule({
   imports: [
     CommonModule,
     CoreRoutingModule,
     SharedModule,
+    ReactiveFormsModule,
   ],
   declarations: [CoreComponents],
   providers: [
diff --git a/src/app/core/interceptors/http-error-response-interceptor.ts b/src/app/core/interceptors/http-error-response-interceptor.ts
index c8bae8b6e53fd88682086548d8078b317ea6006d..a54205a989c1bc62bc6b0ed5342259bb4d5a93a3 100644
--- a/src/app/core/interceptors/http-error-response-interceptor.ts
+++ b/src/app/core/interceptors/http-error-response-interceptor.ts
@@ -18,7 +18,6 @@ export class HttpErrorResponseInterceptor implements HttpInterceptor {
         }
       },
       (err) => {
-        console.log(err);
         if (err instanceof HttpErrorResponse) {
           switch (err.status) {
             case 401:
diff --git a/src/app/core/models/email.model.ts b/src/app/core/models/email.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c9a21ce1c9dbff20190a705efaa824be6e3086d9
--- /dev/null
+++ b/src/app/core/models/email.model.ts
@@ -0,0 +1,26 @@
+import { environment } from '../../../environments/environment';
+
+export interface IContactForm {
+  email: string;
+  emailConfirmation: string;
+  subject: string;
+  text: string;
+  firstname: string;
+  lastname: string;
+}
+
+export class Email {
+  from: string;
+  subject: string;
+  firstname: string;
+  lastname: string;
+  text: string;
+
+  constructor(contactForm: IContactForm) {
+    this.subject = contactForm.subject;
+    this.text = contactForm.text;
+    this.from = contactForm.email;
+    this.firstname = contactForm.firstname;
+    this.lastname = contactForm.lastname;
+  }
+}
diff --git a/src/app/core/models/index.ts b/src/app/core/models/index.ts
index 804ec59ded0ef6ad842ec93fe8c958a85456e135..0d3c38d322c55b79a68bf7e0e53594f3ac8a21c1 100644
--- a/src/app/core/models/index.ts
+++ b/src/app/core/models/index.ts
@@ -1,5 +1,7 @@
 import { Notification, INotification } from './notification.model';
 import { IMatomoResponse } from './matomo.model';
+import { IContactForm, Email } from './email.model';
 
 export { Notification, INotification };
 export { IMatomoResponse };
+export { IContactForm, Email };
diff --git a/src/app/core/services/email.service.ts b/src/app/core/services/email.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9ad680edb69015df6f16c1a6780ce253a1c61149
--- /dev/null
+++ b/src/app/core/services/email.service.ts
@@ -0,0 +1,16 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { environment } from '../../../environments/environment';
+import { Email } from '../models';
+
+@Injectable()
+export class EmailService {
+
+  constructor(
+    private _httpClient: HttpClient,
+  ) {}
+
+  send(email: Email) {
+    return this._httpClient.post(environment.emailService.url + '/contact', email);
+  }
+}
diff --git a/src/app/core/services/index.ts b/src/app/core/services/index.ts
index ed90907ea1e9a8b600f61fe1ae841317c93fb80e..15ae6b2712fa5254fde435de2ef7bf1e5028a5ac 100644
--- a/src/app/core/services/index.ts
+++ b/src/app/core/services/index.ts
@@ -3,8 +3,9 @@ import { NotificationService } from './notification.service';
 import { MatomoService } from './matomo.service';
 import { NavigationHistoryService } from './navigation-history.service';
 import { StorageService } from './storage.service';
+import { EmailService } from './email.service';
 
-export { ErrorService, NotificationService, MatomoService, NavigationHistoryService };
+export { ErrorService, NotificationService, MatomoService, NavigationHistoryService, EmailService };
 
 // tslint:disable-next-line:variable-name
 export const CoreServices = [
@@ -13,4 +14,5 @@ export const CoreServices = [
   MatomoService,
   NavigationHistoryService,
   StorageService,
+  EmailService,
 ];
diff --git a/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.html b/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.html
index 3b9525d52c7d4973b42f82ba901db2d33ce20c6c..3214aa437eb9790fc53cdb1ecc90c3ef3910bcab 100644
--- a/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.html
+++ b/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.html
@@ -47,7 +47,8 @@
                 {{ generalInfo['parent'].keyTitle }}
               </div>
               <div class="column is-10 is-size-7 even">
-                <a [routerLink]="['/', AppRoutes.research.uri, AppRoutes.datasets.uri, generalInfo['parent'].uuid]">{{ generalInfo['parent'].title }}</a>
+                <a [routerLink]="['/', AppRoutes.research.uri, AppRoutes.datasets.uri, generalInfo['parent'].uuid]">{{
+                  generalInfo['parent'].title }}</a>
               </div>
             </ng-container>
           </div>
@@ -85,8 +86,15 @@
             </ng-container>
           </div>
         </div>
-
+        <div class="contact">
+          <div class="columns is-marginless">
+            <div class="column is-12 title is-size-7">
+              <span i18n="@@dataset.info.questions">You have questions on this dataset, </span>
+              <a i18n="@@dataset.info.contactus" class="link-red" [routerLink]="['/', AppRoutes.contact.uri]" [queryParams]="{ subject: metadata.title }">contact us.</a>
+            </div>
+          </div>
+        </div>
       </div>
     </div>
   </div>
-</ng-container>
+</ng-container>
\ No newline at end of file
diff --git a/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.scss b/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.scss
index cec3249eef9955a73ba4713a68e442dbca4ff45d..bec1e28d4f117c5a09afd69f1b86e5a0e9c80a9c 100644
--- a/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.scss
+++ b/src/app/geosource/components/dataset-detail/dataset-info/dataset-info.component.scss
@@ -36,7 +36,7 @@ div.unitary-description:not(:first-of-type) {
 }
 
 
-.children , .general-info, .articles {
+.children , .general-info, .articles, .contact {
   .column {
     padding-top: 0.3125rem;
     padding-bottom: 0.3125rem;
diff --git a/src/app/geosource/geosource-routing.module.ts b/src/app/geosource/geosource-routing.module.ts
index e1ccd324ab818c99b91e3c33ef6bb5cff72a129f..d17b00236bc3147b151903bedc4a4d67e74e0fea 100644
--- a/src/app/geosource/geosource-routing.module.ts
+++ b/src/app/geosource/geosource-routing.module.ts
@@ -6,7 +6,7 @@ import { AppRoutes } from '../routes';
 
 export const routes: Routes = [
   {
-    path: '',
+    path: AppRoutes.research.uri,
     component: ResearchComponent,
     data: {
       title: AppRoutes.research.title,
diff --git a/src/app/geosource/services/elasticsearch.service.ts b/src/app/geosource/services/elasticsearch.service.ts
index 2b2ff4d273e7d7573dbd5a4a93c7a7c60a9d19a6..cab37974091ddcc1ae1eb47787111178990cc0b3 100644
--- a/src/app/geosource/services/elasticsearch.service.ts
+++ b/src/app/geosource/services/elasticsearch.service.ts
@@ -283,8 +283,8 @@ export class ElasticsearchService {
   }
 
   /*
-  * This request will get one suggestion from the query text
-  * The suggest is based on metadata-fr.title property
+  * This request will get one phrase suggestion out of the query text
+  * cf. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html
   */
   getSuggestion(query: string): Observable<SearchSuggestion> {
     return this._http.request<IElasticsearchResponse>('POST', this.url, {
@@ -293,16 +293,20 @@ export class ElasticsearchService {
           text: query,
           suggestion: {
             phrase: {
-              field: 'data_and_metadata',
+              field: 'data_and_metadata.suggest',
+              // as only the very first suggestion will be used, let's limit the size of the results to 1:
+              size: 1,
+              max_errors: query.split(' ').length,
               highlight: {
                 pre_tag: '<b><i>',
                 post_tag: '</i></b>',
               },
+              analyzer: 'my_search_analyzer',
               direct_generator: [{
-                field: 'data_and_metadata',
-                suggest_mode: 'popular',
-                // prefix_length: 4,
-                min_word_length: 1,
+                field: 'data_and_metadata.suggest',
+                suggest_mode: 'missing',
+                prefix_length: 1,
+                min_word_length: 4,
               }],
             },
           },
diff --git a/src/app/routes.ts b/src/app/routes.ts
index 18c900f31150a428a6b70fbec525cad9fd9ab9a8..27db92a085df95479d39970f1394e216f8f7ed9b 100644
--- a/src/app/routes.ts
+++ b/src/app/routes.ts
@@ -21,6 +21,13 @@ export const AppRoutes = {
       en: 'Accessibility',
     },
   },
+  contact: {
+    uri: 'contact',
+    title: {
+      fr: 'Contact',
+      en: 'Contact',
+    },
+  },
   siteMap: {
     uri: 'plan-du-site',
     title: {
diff --git a/src/app/shared/directives/block-copypaste.directive.ts b/src/app/shared/directives/block-copypaste.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7cb989da64336c3b1758850a9df2f4609dfffdcc
--- /dev/null
+++ b/src/app/shared/directives/block-copypaste.directive.ts
@@ -0,0 +1,20 @@
+import { Directive, HostListener } from '@angular/core';
+
+@Directive({
+  selector: '[blockCopyPaste]',
+})
+export class BlockCopyPasteDirective {
+  constructor() { }
+
+  @HostListener('paste', ['$event']) blockPaste(e: KeyboardEvent) {
+    e.preventDefault();
+  }
+
+  @HostListener('copy', ['$event']) blockCopy(e: KeyboardEvent) {
+    e.preventDefault();
+  }
+
+  @HostListener('cut', ['$event']) blockCut(e: KeyboardEvent) {
+    e.preventDefault();
+  }
+}
diff --git a/src/app/shared/directives/click-outside.directive.ts b/src/app/shared/directives/click-outside.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d89778c8bacbaeb2b1e0d6bee03c4193ac0c7cae
--- /dev/null
+++ b/src/app/shared/directives/click-outside.directive.ts
@@ -0,0 +1,20 @@
+import { Directive, ElementRef, Output, EventEmitter, HostListener } from '@angular/core';
+
+@Directive({
+  selector: '[clickOutside]',
+})
+export class ClickOutsideDirective {
+  constructor(private _elementRef: ElementRef) {
+  }
+
+  @Output()
+  public clickOutside = new EventEmitter();
+
+  @HostListener('document:click', ['$event.target'])
+  public onClick(targetElement) {
+    const clickedInside = this._elementRef.nativeElement.contains(targetElement);
+    if (!clickedInside) {
+      this.clickOutside.emit(null);
+    }
+  }
+}
diff --git a/src/app/shared/directives/index.ts b/src/app/shared/directives/index.ts
index 08d1c25f0ae96ac403d347efe562839a3278f1fb..79989eb79dd7c268f6ed1e4d29230a25cd8e8b87 100644
--- a/src/app/shared/directives/index.ts
+++ b/src/app/shared/directives/index.ts
@@ -1,10 +1,14 @@
 import { PreventDefaultDirective } from './prevent-default.directive';
 import { DynamicLinks } from './dynamic-links';
+import { ClickOutsideDirective } from './click-outside.directive';
+import { BlockCopyPasteDirective } from './block-copypaste.directive';
 
-export { PreventDefaultDirective, DynamicLinks };
+export { PreventDefaultDirective, DynamicLinks, ClickOutsideDirective, BlockCopyPasteDirective };
 
 // tslint:disable-next-line:variable-name
 export const SharedDirectives = [
   PreventDefaultDirective,
   DynamicLinks,
+  ClickOutsideDirective,
+  BlockCopyPasteDirective,
 ];
diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts
index 7534c324adaf40ea2ba484d91de1cc31d6ef667a..40f7139cbc7993534c5baa6c2402fe61de090034 100644
--- a/src/environments/environment.prod.ts
+++ b/src/environments/environment.prod.ts
@@ -23,6 +23,10 @@ export const environment = {
     url: servicesProxyUrl + '/backend',
   },
 
+  emailService: {
+    url: 'https://kong.alpha.grandlyon.com/email',
+  },
+
   // Path to the built app in a particular language
   angularAppHost: {
     fr: '/fr',
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index f32fb6a47b50e6cd4d6aa32e2f22449193910f1b..a5259414d400596e255d2fb252b08dd87513f173 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -11,7 +11,7 @@ export const environment = {
 
   // ElasticSearch
   elasticsearchUrl: {
-    full: servicesProxyUrl + '/elasticsearch2/test-all-in-one-index.full.v8.quadtree',
+    full: servicesProxyUrl + '/elasticsearch2/test-all-in-one-index.full.v9.quadtree',
     meta: servicesProxyUrl + '/elasticsearch/*.meta',
   },
 
@@ -23,6 +23,10 @@ export const environment = {
     url: 'http://localhost:3000',
   },
 
+  emailService: {
+    url: 'https://kong.alpha.grandlyon.com/email',
+  },
+
   // Path to the built app in a particular language
   angularAppHost: {
     fr: '/fr',
diff --git a/src/i18n/contact/contact.fr.ts b/src/i18n/contact/contact.fr.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8136b61273e65e81410a83fdf365546a93134fbd
--- /dev/null
+++ b/src/i18n/contact/contact.fr.ts
@@ -0,0 +1,35 @@
+export const subjects = [
+  {
+    key: 'licenseQuestion',
+    value: 'question sur les licences',
+  },
+  {
+    key: 'technicalQuestion',
+    value: 'question technique',
+  },
+  {
+    key: 'anomalyReport',
+    value: 'signalement d\'anomalie',
+  },
+  {
+    key: 'contactRequest',
+    value: 'demande de contact',
+  },
+  {
+    key: 'infoRequest',
+    value: 'demande d\'information',
+  },
+  {
+    key: 'newDataRequest',
+    value: 'demande de nouvelle donnée',
+  },
+  {
+    key: 'other',
+    value: 'autre',
+  },
+];
+
+export const feedbackMessages = {
+  error: 'Désolé, nous n\'avons pas pu envoyer votre demande, veuillez réessayer ultérieurement',
+  success: 'Votre message a bien été envoyé',
+};
diff --git a/src/i18n/contact/contact.ts b/src/i18n/contact/contact.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c340e7d73203c4ca57c922d316ae6041d33dbcfc
--- /dev/null
+++ b/src/i18n/contact/contact.ts
@@ -0,0 +1,35 @@
+export const subjects = [
+  {
+    key: 'licenseQuestion',
+    value: 'question about licences',
+  },
+  {
+    key: 'technicalQuestion',
+    value: 'technical question',
+  },
+  {
+    key: 'anomalyReport',
+    value: 'anomaly report',
+  },
+  {
+    key: 'contactRequest',
+    value: 'request contact',
+  },
+  {
+    key: 'infoRequest',
+    value: 'information request',
+  },
+  {
+    key: 'newDataRequest',
+    value: 'request for new data',
+  },
+  {
+    key: 'other',
+    value: 'other',
+  },
+];
+
+export const feedbackMessages = {
+  error: 'Sorry, we couldn\'t send your message, please try again later',
+  success: 'Your message has been sent successfully.',
+};
diff --git a/src/i18n/messages.en.xlf b/src/i18n/messages.en.xlf
index ab6eba3dd56c666ec50c6a76f2091babc57e0a6b..69beaa12491b596941485abca3eb6a33f0072497 100644
--- a/src/i18n/messages.en.xlf
+++ b/src/i18n/messages.en.xlf
@@ -259,6 +259,14 @@
          <source>Number of views (last 30 days)</source>
          <target>Number of views (last 30 days)</target>
       </trans-unit>
+      <trans-unit id="dataset.info.questions" datatype="html">
+         <source>You have questions on this dataset, </source>
+         <target>You have questions on this dataset, </target>
+      </trans-unit>
+      <trans-unit id="dataset.info.contactus" datatype="html">
+         <source>contact us.</source>
+         <target>contact us.</target>
+      </trans-unit>
       <trans-unit id="dataset.data.unavailableInfo" datatype="html">
          <source>Unavailable information for this data</source>
          <target>Unavailable information for this data</target>
@@ -287,6 +295,90 @@
          <source>RESEARCH</source>
          <target>RESEARCH</target>
       </trans-unit>
+      <trans-unit id="contact.contactUs" datatype="html">
+         <source>Contact us</source>
+         <target>Contact us</target>
+      </trans-unit>
+      <trans-unit id="contact.contactForm" datatype="html">
+         <source>Form contact</source>
+         <target>Form contact</target>
+      </trans-unit>
+      <trans-unit id="contact.identity" datatype="html">
+         <source>Identity</source>
+         <target>Identity</target>
+      </trans-unit>
+      <trans-unit id="contact.lastname" datatype="html">
+         <source>Lastname</source>
+         <target>Lastname</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingLastname" datatype="html">
+         <source>You must indicate your lastname.</source>
+         <target>You must indicate your lastname.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.forbiddenCharacters" datatype="html">
+         <source>Special characters are forbidden.</source>
+         <target>Special characters are forbidden.</target>
+      </trans-unit>
+      <trans-unit id="contact.firstname" datatype="html">
+         <source>Firstname</source>
+         <target>Firstname</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingFirstname" datatype="html">
+         <source>You must indicate a firstname.</source>
+         <target>You must indicate a firstname.</target>
+      </trans-unit>
+      <trans-unit id="contact.email" datatype="html">
+         <source>Email</source>
+         <target>Email</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingEmail" datatype="html">
+         <source>You must enter an email address.</source>
+         <target>You must enter an email address.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.invalidEmail" datatype="html">
+         <source>You must enter a valid email address.</source>
+         <target>You must enter a valid email address.</target>
+      </trans-unit>
+      <trans-unit id="contact.emailConfirmation" datatype="html">
+         <source>Confirm your email address</source>
+         <target>Confirm your email address</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingConfirmationEmail" datatype="html">
+         <source>You must confirm your email address.</source>
+         <target>You must confirm your email address.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.confirmationEmailNotCorresponding" datatype="html">
+         <source>You must enter the same email address.</source>
+         <target>You must enter the same email address.</target>
+      </trans-unit>
+       <trans-unit id="contact.message" datatype="html">
+         <source>Message</source>
+         <target>Message</target>
+      </trans-unit>
+      <trans-unit id="contact.subject" datatype="html">
+         <source>Subject</source>
+         <target>Subject</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingSubject" datatype="html">
+         <source>You must enter a subject.</source>
+         <target>You must enter a subject.</target>
+      </trans-unit>
+      <trans-unit id="contact.messageField" datatype="html">
+         <source>Message</source>
+         <target>Message</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.invalidMessage" datatype="html">
+         <source>You must enter a message.</source>
+         <target>You must enter a message.</target>
+      </trans-unit>
+      <trans-unit id="contact.send" datatype="html">
+         <source>Send</source>
+         <target>Send</target>
+      </trans-unit>
+      <trans-unit id="contact.cancel" datatype="html">
+         <source>Cancel</source>
+         <target>Cancel</target>
+      </trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/i18n/messages.fr.xlf b/src/i18n/messages.fr.xlf
index ace293798ac696b708bfa1c5bae25e643bbddfad..3aa38827300b53531b25d547d26f728350070947 100644
--- a/src/i18n/messages.fr.xlf
+++ b/src/i18n/messages.fr.xlf
@@ -267,6 +267,14 @@
          <source>Number of views (last 30 days)</source>
          <target>Nombre de vues (30 derniers jours)</target>
       </trans-unit>
+      <trans-unit id="dataset.info.questions" datatype="html">
+         <source>You have questions on this dataset, </source>
+         <target>Vous avez des questions sur ce jeu de données, </target>
+      </trans-unit>
+      <trans-unit id="dataset.info.contactus" datatype="html">
+         <source>contact us.</source>
+         <target>contactez-nous.</target>
+      </trans-unit>
       <trans-unit id="dataset.data.unavailableInfo" datatype="html">
          <source>Unavailable information for this data</source>
          <target>Information non disponible pour cette donnée</target>
@@ -295,6 +303,90 @@
          <source>RESEARCH</source>
          <target>RECHERCHER</target>
       </trans-unit>
+      <trans-unit id="contact.contactUs" datatype="html">
+         <source>Contact us</source>
+         <target>Contactez nous</target>
+      </trans-unit>
+      <trans-unit id="contact.contactForm" datatype="html">
+         <source>Form contact</source>
+         <target>Formulaire de contact</target>
+      </trans-unit>
+      <trans-unit id="contact.identity" datatype="html">
+         <source>Identity</source>
+         <target>Identité</target>
+      </trans-unit>
+      <trans-unit id="contact.lastname" datatype="html">
+         <source>Lastname</source>
+         <target>Nom de famille</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingLastname" datatype="html">
+         <source>You must indicate your lastname.</source>
+         <target>Veuillez indiquer votre nom de famille.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.forbiddenCharacters" datatype="html">
+         <source>Special characters are forbidden.</source>
+         <target>Les caractères spéciaux sont interdits.</target>
+      </trans-unit>
+      <trans-unit id="contact.firstname" datatype="html">
+         <source>Firstname</source>
+         <target>Prénom</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingFirstname" datatype="html">
+         <source>You must indicate a firstname.</source>
+         <target>Veuillez indiquer votre prénom.</target>
+      </trans-unit>
+      <trans-unit id="contact.email" datatype="html">
+         <source>Email</source>
+         <target>Email</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingEmail" datatype="html">
+         <source>You must enter an email address.</source>
+         <target>Veuillez saisir votre adresse email.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.invalidEmail" datatype="html">
+         <source>You must enter a valid email address.</source>
+         <target>Veuillez saisir une adresse email valide.</target>
+      </trans-unit>
+      <trans-unit id="contact.emailConfirmation" datatype="html">
+         <source>Confirm your email address</source>
+         <target>Confirmez votre adresse email.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingConfirmationEmail" datatype="html">
+         <source>You must confirm your email address.</source>
+         <target>Veuillez confirmer votre adresse email.</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.confirmationEmailNotCorresponding" datatype="html">
+         <source>You must enter the same email address.</source>
+         <target>La confirmation de l'email ne correspond pas à l'adresse email saisie.</target>
+      </trans-unit>
+      <trans-unit id="contact.message" datatype="html">
+         <source>Message</source>
+         <target>Message</target>
+      </trans-unit>
+      <trans-unit id="contact.subject" datatype="html">
+         <source>Subject</source>
+         <target>Sujet</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.missingSubject" datatype="html">
+         <source>You must enter a subject.</source>
+         <target>Veuillez saisir un sujet.</target>
+      </trans-unit>
+      <trans-unit id="contact.messageField" datatype="html">
+         <source>Message</source>
+         <target>Message</target>
+      </trans-unit>
+      <trans-unit id="contact.errors.invalidMessage" datatype="html">
+         <source>You must enter a message.</source>
+         <target>Veuillez saisir votre message.</target>
+      </trans-unit>
+      <trans-unit id="contact.send" datatype="html">
+         <source>Send</source>
+         <target>Envoyer</target>
+      </trans-unit>
+      <trans-unit id="contact.cancel" datatype="html">
+         <source>Cancel</source>
+         <target>Annuler</target>
+      </trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/scss/variables.scss b/src/scss/variables.scss
index 2521a1cbfe00bb2b96dff82a3b5bf0aa5fcbfc10..43592a0686a262a0ca66325723bbbccf2058bd87 100644
--- a/src/scss/variables.scss
+++ b/src/scss/variables.scss
@@ -3,7 +3,8 @@
 // 2. Set your own initial variables
 $main: #17252b;
 $red: #d5232a;
-$green: #04BA5B ;
+$green: #04BA5B;
+$dark-blue: #333745;
 
 $app-background-color: rgb(252, 252, 252);
 
diff --git a/src/styles.scss b/src/styles.scss
index 8b2428c13aa347b7750472db023c22e8b2450e01..96eed87e5d9cf812640d63328e850eedecee8700 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -154,4 +154,32 @@ a:hover {
   }
 }
 
+.button-gl {
+  background: linear-gradient(to bottom, #ff6459, $red);
+  border-radius: 2px;
+  border-width: 0;
+  font-size: $size-6;
+  color: white;
+  text-transform: uppercase;
+  &:hover, &:focus {
+    color:white;
+    background: $red;
+  }
+  &.is-outlined {
+    border: 2px solid $dark-blue;
+    font-weight: bold;
+    color: $dark-blue;
+    background: transparent;
+
+    &:hover, &:focus {
+      border-color: $red;
+    }
+  }
+}
+
+.link-red {
+  color: $red;
+  text-decoration: underline;
+}
+
 @import "./scss/wordpress-style";
\ No newline at end of file