diff --git a/Resources/js/widget/file_upload.js b/Resources/js/widget/file_upload.js
index 2fd78ee2e3cc9ebcf726ceefd420447e0ed09bf4..d8d67341654bd187547e74adde1cda696e3492e9 100644
--- a/Resources/js/widget/file_upload.js
+++ b/Resources/js/widget/file_upload.js
@@ -2,25 +2,26 @@
  * Copyright (C) 2015 IRSTEA
  * All rights reserved.
  */
-(function($, Translator) {
+(function ($, Translator) {
 
-    var formatFileSize = function(size) {
+    var formatFileSize = function (size) {
             var unit;
-            if(size > 1000000000) {
-                size = (size/1000000000).toFixed(2);
+            if (size > 1000000000) {
+                size = (size / 1000000000).toFixed(2);
                 unit = 'Gi';
-            } else if(size > 1000000) {
-                size = (size/1000000).toFixed(2);
+            } else if (size > 1000000) {
+                size = (size / 1000000).toFixed(2);
                 unit = 'Mi';
-            } else if(size > 1000) {
-                size = (size/1000).toFixed(2);
-                unit ='Ki';
+            } else if (size > 1000) {
+                size = (size / 1000).toFixed(2);
+                unit = 'Ki';
             } else {
                 unit = '';
             }
-            return Translator.trans('file_size(%size%,%unit%)', {size:size, unit:unit}, 'file_upload');
+            'UPLOADING !'
+            return Translator.trans('file_size(%size%,%unit%)', {size: size, unit: unit}, 'file_upload');
         },
-        formatBitrate = function(rate) {
+        formatBitrate = function (rate) {
             return formatFileSize(rate) + '/s';
         };
 
@@ -29,29 +30,52 @@
 
     /** Plugin irsteaFileUpload.
      */
-    $.fn.irsteaFileUpload = function(options) {
-
-        var $this             = $(this),
-            $button           = $this.find('.fileinput-button'),
-            $entries          = $this.find('.fileinput-entries'),
-            nextIndex         = $entries.find('.fileinput-entry').length,
-            createUrl         = options.createUrl,
-            uploadPrototype   = options.uploadPrototype,
+    $.fn.irsteaFileUpload = function (options) {
+
+        var $this = $(this),
+            $button = $this.find('.fileinput-button'),
+            input = $this.find(':file')[0],
+            $entries = $this.find('.fileinput-entries'),
+            nextIndex = $entries.find('.fileinput-entry').length,
+            createUrl = options.createUrl,
+            uploadPrototype = options.uploadPrototype,
             downloadPrototype = options.downloadPrototype,
-            csrfQuery         = '?token=' + options.csrfToken;
+            csrfQuery = '?token=' + options.csrfToken;
 
         delete options.createUrl;
         delete options.uploadPrototype;
         delete options.downloadPrototype;
         delete options.csrfToken;
 
-        if(options.acceptFileTypes) {
+        if (options.acceptFileTypes) {
             options.acceptFileTypes = new RegExp('^' + options.acceptFileTypes + '$');
         }
 
-        var showError = function(entry, message) {
+        var checkValidity = function () {
+                var counts = {
+                        upload: $entries.find('.template-upload').length,
+                        download: $entries.find('.template-download').length,
+                        error: $entries.find('.alert-danger').length,
+                    },
+                    error = '';
+
+                if (counts.upload > 0) {
+                    error = Translator.trans('file_upload.running_upload');
+
+                } else if (counts.error > 0) {
+                    error = Translator.trans('file_upload.upload_error');
+
+                } else if (options.required && counts.download < 1) {
+                    error = Translator.trans('file_upload.required_file');
+                }
+
+                input.setCustomValidity(error);
+
+                // console.debug(input, counts, input.validationMessage, input.validity);
+            },
+            showError = function (entry, message) {
                 var $this = $(entry);
-                if(message) {
+                if (message) {
                     $this.find('.error').text(Translator.trans(message));
                 }
                 $this.addClass('alert alert-danger');
@@ -62,20 +86,19 @@
                 $this.find('.description').remove();
                 $this.find('.id').remove();
             },
-            updateDisplay = function() {
+            updateDisplay = function (event) {
                 var hasEntry = false;
-                $entries.find('.fileinput-entry').each(function() {
+                $entries.find('.fileinput-entry').each(function () {
                     var data = $(this).data('data');
-                    if(data && data.files.error) {
+                    if (data && data.files.error) {
                         showError(this, data.files[0].error);
                     }
                     hasEntry = true;
                 });
                 $button.toggle(options.multiple || !hasEntry);
+                checkValidity();
             };
 
-        updateDisplay();
-
         // Activation
         $button.fileupload($.extend(
             options,
@@ -89,7 +112,7 @@
                 filesContainer: $this.find('.fileinput-entries'),
                 dropZone: $this,
                 i18n: Translator.trans,
-                uploadTemplate: function(data) {
+                uploadTemplate: function (data) {
                     var rows = $();
                     $.each(data.files, function (index, file) {
                         var row = $(uploadPrototype);
@@ -103,7 +126,7 @@
                     });
                     return rows;
                 },
-                downloadTemplate: function(data) {
+                downloadTemplate: function (data) {
                     var rows = $();
                     $.each(data.files, function (index, file) {
                         var row = $(downloadPrototype.replace(/__index__/g, nextIndex++));
@@ -122,10 +145,10 @@
                             .attr('data-url', file.delete_url + csrfQuery);
                         row.find('input.id')
                             .val(file.id);
-                        if(file.icon && file.icon !== 'file') {
+                        if (file.icon && file.icon !== 'file') {
                             row.find('.icon')
                                 .removeClass('fa-file-o')
-                                .addClass('fa-file-'+file.icon+'-o');
+                                .addClass('fa-file-' + file.icon + '-o');
                         }
                     });
                     return rows;
@@ -135,8 +158,8 @@
                         file = data.files[0];
                     $.post(
                         createUrl,
-                        { file: { name: file.name, size: file.size, type: file.type, lastModified: file.lastModified } },
-                        function(response) {
+                        {file: {name: file.name, size: file.size, type: file.type, lastModified: file.lastModified}},
+                        function (response) {
                             file.icon = response.icon;
                             data.url = response.put_url + csrfQuery;
                             data.delete_url = response.delete_url;
@@ -144,7 +167,7 @@
                             data.jqXHR = $this.fileupload('send', data);
                         }
                     )
-                        .fail(function(jqXHR, textStatus, errorThrown) {
+                        .fail(function (jqXHR, textStatus, errorThrown) {
                             file.error = textStatus === "error" ? errorThrown : ('Error #' + jqXHR.status);
                             data.files.error = true;
                             showError(data.context, file.error);
@@ -153,7 +176,7 @@
                     return false;
                 },
                 progress: function (e, data) {
-                    if(!data.context || e.isDefaultPrevented()) {
+                    if (!data.context || e.isDefaultPrevented()) {
                         return;
                     }
                     var percent = data.loaded / data.total * 100,
@@ -162,21 +185,22 @@
                         var $this = $(data.context);
                         $this.find('.progress').show();
                         $this.find('.progress-bar').css('width', percent + '%').attr('aria-valuenow', percentText);
-                        $this.find('.progress-text').show().html(percentText + '% ('+formatBitrate(data.bitrate)+')');
+                        $this.find('.progress-text').show().html(percentText + '% (' + formatBitrate(data.bitrate) + ')');
                     });
                 },
-                getFilesFromResponse: function(data) {
+                getFilesFromResponse: function (data) {
                     var files = [];
-                    $.each(data.files, function(index, file) {
+                    $.each(data.files, function (index, file) {
                         files.push($.extend(file, data.result.files[index]));
                     });
                     return files;
                 },
             }
         )).bind({
-            fileuploadfailed: function (e, data) {
-                if(data.delete_url) {
-                    $.ajax(data.delete_url + csrfQuery, { type: data.delete_type });
+            fileuploadfailed: function (event, data) {
+                if (data.delete_url) {
+                    $.ajax(data.delete_url + csrfQuery, {type: data.delete_type});
+                    checkValidity();
                 }
             },
             fileuploadadded: updateDisplay,
@@ -185,10 +209,11 @@
             fileuploadprocessalways: updateDisplay
         });
 
-        if(options.disabled || options.readonly) {
+        if (options.disabled || options.readonly) {
             $button.fileupload('disable');
         }
 
+        updateDisplay();
     };
 
 })(jQuery, Translator);
diff --git a/Resources/views/Form/file_upload.html.twig b/Resources/views/Form/file_upload.html.twig
index 5d32376d84b5ba05c742bbe0d7a11f9447e2f350..e59624b304a3b9018b340eb8c211dbdec6de3344 100644
--- a/Resources/views/Form/file_upload.html.twig
+++ b/Resources/views/Form/file_upload.html.twig
@@ -49,7 +49,7 @@
         </div>
         <div class="fileinput-button btn btn-default btn-xs">
             <span>{{ irstea_icon('upload') }}&nbsp;{% trans %}button.upload{% endtrans %}</span>
-            <input type="file" name="_hack_{{ full_name }}"
+            <input type="file" name="_hack_{{ full_name }}" data-map-errors-to="#{{ id }}"
                 {%- if multiple %} multiple="multiple"{% endif -%}
                 {%- if disabled or read_only %} disabled="disabled"{% endif -%}
             />