diff --git a/core/modules/user/user.es6.js b/core/modules/user/user.es6.js
index 4739e1528d43b9bb48baa21434fdac5a13f0ce68..a91b9a1239847c8e6eab3ca00d5561b490461599 100644
--- a/core/modules/user/user.es6.js
+++ b/core/modules/user/user.es6.js
@@ -34,18 +34,14 @@
         $passwordInputParentWrapper
           .find('input.js-password-confirm')
           .parent()
-          .append(
-            `<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm">${
-              translate.confirmTitle
-            } <span></span></div>`,
-          )
+          .append(Drupal.theme('passwordConfirmMessage', translate))
           .addClass('confirm-parent');
 
         const $confirmInput = $passwordInputParentWrapper.find(
           'input.js-password-confirm',
         );
         const $confirmResult = $passwordInputParentWrapper.find(
-          'div.js-password-confirm',
+          'div.js-password-confirm-message',
         );
         const $confirmChild = $confirmResult.find('span');
 
diff --git a/core/modules/user/user.js b/core/modules/user/user.js
index ec9735cf08a59920128f79bc109cc82c17f20aa4..40852ff8bcb8247d8efdb35fe41457db1b38a90d 100644
--- a/core/modules/user/user.js
+++ b/core/modules/user/user.js
@@ -19,10 +19,10 @@
 
         $passwordInputParent.addClass('password-parent');
 
-        $passwordInputParentWrapper.find('input.js-password-confirm').parent().append('<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm">' + translate.confirmTitle + ' <span></span></div>').addClass('confirm-parent');
+        $passwordInputParentWrapper.find('input.js-password-confirm').parent().append(Drupal.theme('passwordConfirmMessage', translate)).addClass('confirm-parent');
 
         var $confirmInput = $passwordInputParentWrapper.find('input.js-password-confirm');
-        var $confirmResult = $passwordInputParentWrapper.find('div.js-password-confirm');
+        var $confirmResult = $passwordInputParentWrapper.find('div.js-password-confirm-message');
         var $confirmChild = $confirmResult.find('span');
 
         if (settings.password.showStrengthIndicator) {
diff --git a/core/modules/user/user.libraries.yml b/core/modules/user/user.libraries.yml
index 73e4e15814686fe538a964a711efb69e86de0e6a..0e6e9533a2e536ed095d95afb19f44f6d7eb143e 100644
--- a/core/modules/user/user.libraries.yml
+++ b/core/modules/user/user.libraries.yml
@@ -2,6 +2,7 @@ drupal.user:
   version: VERSION
   js:
     user.js: {}
+    user.theme.js: {}
   css:
     component:
       css/user.module.css: {}
diff --git a/core/modules/user/user.theme.es6.js b/core/modules/user/user.theme.es6.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3e14650366e6e2d3244f59249323a4748425e2e
--- /dev/null
+++ b/core/modules/user/user.theme.es6.js
@@ -0,0 +1,17 @@
+/**
+ * @file
+ * Theme elements for user password forms.
+ */
+
+(Drupal => {
+  /**
+   * Constucts a password confirm message element
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.passwordConfirmMessage = translate =>
+    `<div aria-live="polite" aria-atomic="true" class="password-confirm-message js-password-confirm-message">${
+      translate.confirmTitle
+    } <span></span></div>`;
+})(Drupal);
diff --git a/core/modules/user/user.theme.js b/core/modules/user/user.theme.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b7b0280c887b471907a1f84a3516c31a80c92a9
--- /dev/null
+++ b/core/modules/user/user.theme.js
@@ -0,0 +1,12 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function (Drupal) {
+  Drupal.theme.passwordConfirmMessage = function (translate) {
+    return "<div aria-live=\"polite\" aria-atomic=\"true\" class=\"password-confirm-message js-password-confirm-message\">" + translate.confirmTitle + " <span></span></div>";
+  };
+})(Drupal);
\ No newline at end of file
diff --git a/core/themes/stable/js/user.theme.es6.js b/core/themes/stable/js/user.theme.es6.js
new file mode 100644
index 0000000000000000000000000000000000000000..4f10529b007e5a948883b0335854e42f24d4d9af
--- /dev/null
+++ b/core/themes/stable/js/user.theme.es6.js
@@ -0,0 +1,17 @@
+/**
+ * @file
+ * Stable theme overrides for user password forms.
+ */
+
+(Drupal => {
+  /**
+   * Constucts a password confirm message element
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.passwordConfirmMessage = translate =>
+    `<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm js-password-confirm-message">${
+      translate.confirmTitle
+    } <span></span></div>`;
+})(Drupal);
diff --git a/core/themes/stable/js/user.theme.js b/core/themes/stable/js/user.theme.js
new file mode 100644
index 0000000000000000000000000000000000000000..a85ae4e43b819d6aac60d0130331b0f33f45d4aa
--- /dev/null
+++ b/core/themes/stable/js/user.theme.js
@@ -0,0 +1,12 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function (Drupal) {
+  Drupal.theme.passwordConfirmMessage = function (translate) {
+    return "<div aria-live=\"polite\" aria-atomic=\"true\" class=\"password-confirm js-password-confirm js-password-confirm-message\">" + translate.confirmTitle + " <span></span></div>";
+  };
+})(Drupal);
\ No newline at end of file
diff --git a/core/themes/stable/stable.info.yml b/core/themes/stable/stable.info.yml
index 2d2aa148c5c6544a13dd086148a9f7097fc36ecb..c14e3966b5dedadd8834360cd8ab853f5f00c619 100644
--- a/core/themes/stable/stable.info.yml
+++ b/core/themes/stable/stable.info.yml
@@ -308,3 +308,7 @@ libraries-override:
       theme:
         css/views_ui.admin.theme.css: css/views_ui/views_ui.admin.theme.css
         css/views_ui.contextual.css: css/views_ui/views_ui.contextual.css
+
+libraries-extend:
+  user/drupal.user:
+    - stable/drupal.user
diff --git a/core/themes/stable/stable.libraries.yml b/core/themes/stable/stable.libraries.yml
new file mode 100644
index 0000000000000000000000000000000000000000..354e1b1e9e2413569487ff0d16b956f7f8328e5b
--- /dev/null
+++ b/core/themes/stable/stable.libraries.yml
@@ -0,0 +1,4 @@
+drupal.user:
+  version: VERSION
+  js:
+    js/user.theme.js: {}