diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index 252e0db24d1e6889318ec21fcdf906db9ee938af..fde8c4ef14b8b6324b3a72715ceafeea2ad876bb 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -549,6 +549,9 @@
         ajax.ajaxing = true;
         return ajax.beforeSend(xmlhttprequest, options);
       },
+      uploadProgress(event, position, total, percentComplete) {
+        return ajax.uploadProgress(event, position, total, percentComplete);
+      },
       success(response, status, xmlhttprequest) {
         ajax.preCommandsFocusedElementSelector =
           document.activeElement.getAttribute('data-drupal-selector');
@@ -961,6 +964,35 @@
   Drupal.theme.ajaxProgressMessage = (message) =>
     `<div class="message">${message}</div>`;
 
+  /**
+   * Processes file upload progress if needed.
+   * @param event
+   * @param position
+   * @param total
+   * @param percentComplete
+   */
+  function bytesToSize(bytes, separator = '') {
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    if (bytes === 0) return '0 Bytes';
+    const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
+    if (i === 0) return `${bytes}${separator}${sizes[i]}`;
+    return `${(bytes / 1024 ** i).toFixed(1)}${separator}${sizes[i]}`;
+  }
+  Drupal.Ajax.prototype.uploadProgress = function (
+    event,
+    position,
+    total,
+    percentComplete,
+  ) {
+    if (this.progress.type === 'bar') {
+      const message = Drupal.t('Uploading... (@current of @total)', {
+        '@current': bytesToSize(position),
+        '@total': bytesToSize(total),
+      });
+      this.progress.object.setProgress(percentComplete, message);
+    }
+  };
+
   /**
    * Provide a wrapper for the AJAX progress bar element.
    *
diff --git a/core/modules/file/file.install b/core/modules/file/file.install
index bce27470f19d6eb8c342c28ef390cf3b292243f0..00e2c276516c77bdd3d67bb2b8f1811c309dfa1d 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -63,46 +63,13 @@ function file_schema(): array {
  * Display information about getting upload progress bars working.
  */
 function file_requirements($phase): array {
-  $requirements = [];
-
-  if ($phase != 'runtime') {
-    return $requirements;
-  }
-
-  $server_software = \Drupal::request()->server->get('SERVER_SOFTWARE', '');
-
-  // Get the web server identity.
-  $is_nginx = preg_match("/Nginx/i", $server_software);
-  $is_apache = preg_match("/Apache/i", $server_software);
-  $fastcgi = $is_apache && ((str_contains($server_software, 'mod_fastcgi') || str_contains($server_software, 'mod_fcgi')));
-
-  // Check the uploadprogress extension is loaded.
-  if (extension_loaded('uploadprogress')) {
-    $value = t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
-    $description = NULL;
-  }
-  else {
-    $value = t('Not enabled');
-    $description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
-  }
-
-  // Adjust the requirement depending on what the server supports.
-  if (!$is_apache && !$is_nginx) {
-    $value = t('Not enabled');
-    $description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.');
-  }
-  elseif ($fastcgi) {
-    $value = t('Not enabled');
-    $description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
-  }
-
-  $requirements['file_progress'] = [
-    'title' => t('Upload progress'),
-    'value' => $value,
-    'description' => $description,
+  return [
+    'file_progress' => [
+      'title' => t('jQuery.form uploadProgress'),
+      'value' => t('jQuery.form uploadProgress'),
+      'description' => t('Drupal uses client side jQuery.form uploadProgress. No extensions are required.'),
+    ],
   ];
-
-  return $requirements;
 }
 
 /**
diff --git a/core/modules/file/src/Controller/FileWidgetAjaxController.php b/core/modules/file/src/Controller/FileWidgetAjaxController.php
index 25bc02c3da00e7fc8525233a00816b7087aa03dd..c8075e18d3ec1932113ece1f7659a7ea9a94d510 100644
--- a/core/modules/file/src/Controller/FileWidgetAjaxController.php
+++ b/core/modules/file/src/Controller/FileWidgetAjaxController.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\file\Controller;
 
-use Drupal\Core\StringTranslation\ByteSizeMarkup;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
@@ -22,23 +21,7 @@ class FileWidgetAjaxController {
    *   A JsonResponse object.
    */
   public function progress($key) {
-    $progress = [
-      'message' => $this->t('Starting upload...'),
-      'percentage' => -1,
-    ];
-
-    if (extension_loaded('uploadprogress')) {
-      $status = uploadprogress_get_info($key);
-      if (isset($status['bytes_uploaded']) && !empty($status['bytes_total'])) {
-        $progress['message'] = $this->t('Uploading... (@current of @total)', [
-          '@current' => ByteSizeMarkup::create($status['bytes_uploaded']),
-          '@total' => ByteSizeMarkup::create($status['bytes_total']),
-        ]);
-        $progress['percentage'] = round(100 * $status['bytes_uploaded'] / $status['bytes_total']);
-      }
-    }
-
-    return new JsonResponse($progress);
+    return new JsonResponse(TRUE);
   }
 
 }
diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php
index 5fc3ae753eaaf9f21078c060b131abb1b537d68c..87aa141f616afd805e3e087feacbb9969db686c9 100644
--- a/core/modules/file/src/Element/ManagedFile.php
+++ b/core/modules/file/src/Element/ManagedFile.php
@@ -275,18 +275,9 @@ public static function processManagedFile(&$element, FormStateInterface $form_st
     ];
 
     // Add progress bar support to the upload if possible.
-    if ($element['#progress_indicator'] == 'bar' && extension_loaded('uploadprogress')) {
+    if ($element['#progress_indicator'] == 'bar') {
       $upload_progress_key = mt_rand();
 
-      $element['UPLOAD_IDENTIFIER'] = [
-        '#type' => 'hidden',
-        '#value' => $upload_progress_key,
-        '#attributes' => ['class' => ['file-progress']],
-        // Uploadprogress extension requires this field to be at the top of
-        // the form.
-        '#weight' => -20,
-      ];
-
       // Add the upload progress callback.
       $element['upload_button']['#ajax']['progress']['url'] = Url::fromRoute('file.ajax_progress', ['key' => $upload_progress_key]);
 
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index 62db3ddf1a43e96008fe042c4cf02e23aa09d57d..045340dda1d9562bcf3c7ae2ffc55578e3db9b86 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -70,7 +70,6 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
       '#default_value' => $this->getSetting('progress_indicator'),
       '#description' => $this->t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
       '#weight' => 16,
-      '#access' => extension_loaded('uploadprogress'),
     ];
     return $element;
   }