diff --git a/core/misc/announce.js b/core/misc/announce.js
index dbefeb6..fb5ff2f 100644
--- a/core/misc/announce.js
+++ b/core/misc/announce.js
@@ -26,7 +26,7 @@
    * to the DOM.
    */
   Drupal.behaviors.drupalAnnounce = {
-    attach: function (context) {
+    attach: function () {
       // Create only one aria-live element.
       if (!liveElement) {
         liveElement = document.createElement('div');
@@ -42,38 +42,44 @@
   /**
    * Concatenates announcements to a single string; appends to the live region.
    */
-  function announce () {
+  function processAnnounce () {
     var text = [];
     var priority = 'polite';
     var announcement;
 
-    // Create an array of announcement strings to be joined and appended to the
-    // aria live region.
-    for (var i = 0, il = announcements.length; i < il; i++) {
-      announcement = announcements.pop();
-      text.unshift(announcement.text);
-      // If any of the announcements has a priority of assertive then the group
-      // of joined announcements will have this priority.
-      if (announcement.priority === 'assertive') {
-        priority = 'assertive';
+    if (announcements.length) {
+      // Create an array of announcement strings to be joined and appended to the
+      // aria live region.
+      for (var i = 0, il = announcements.length; i < il; i++) {
+        announcement = announcements.pop();
+        text.unshift(announcement.text);
+        // If any of the announcements has a priority of assertive then the group
+        // of joined announcements will have this priority.
+        if (announcement.priority === 'assertive') {
+          priority = 'assertive';
+        }
       }
-    }
 
-    if (text.length) {
-      // Clear the liveElement so that repeated strings will be read.
-      liveElement.innerHTML = '';
-      // Set the busy state to true until the node changes are complete.
-      liveElement.setAttribute('aria-busy', 'true');
-      // Set the priority to assertive, or default to polite.
-      liveElement.setAttribute('aria-live', priority);
-      // Print the text to the live region. Text should be run through
-      // Drupal.t() before being passed to Drupal.announce().
-      liveElement.innerHTML = text.join('\n');
-      // The live text area is updated. Allow the AT to announce the text.
-      liveElement.setAttribute('aria-busy', 'false');
+      if (text.length) {
+        // Clear the liveElement so that repeated strings will be read.
+        liveElement.innerHTML = '';
+        // Set the busy state to true until the node changes are complete.
+        liveElement.setAttribute('aria-busy', 'true');
+        // Set the priority to assertive, or default to polite.
+        liveElement.setAttribute('aria-live', priority);
+        // Print the text to the live region. Text should be run through
+        // Drupal.t() before being passed to Drupal.announce().
+        liveElement.innerHTML = text.join('\n');
+        // The live text area is updated. Allow the AT to announce the text.
+        liveElement.setAttribute('aria-busy', 'false');
+      }
     }
   }
 
+  // 200 ms is right at the cusp where humans notice a pause, so we will wait
+  // at most this much time before the set of queued announcements is read.
+  var debouncedProcessAnnounce = debounce(processAnnounce, 200);
+
   /**
    * Triggers audio UAs to read the supplied text.
    *
@@ -98,11 +104,9 @@
     // announcements will be concatenated and read in sequence.
     announcements.push({
       text: text,
-      priority: priority
+      priority: priority || 'polite'
     });
-    // Immediately invoke the function that debounce returns. 200 ms is right at
-    // the cusp where humans notice a pause, so we will wait
-    // at most this much time before the set of queued announcements is read.
-    return (debounce(announce, 200)());
+    debouncedProcessAnnounce(announcements);
   };
+
 }(Drupal, Drupal.debounce));
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 78905da..b0f965f 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -923,6 +923,7 @@ function system_library_info() {
       array('system', 'drupal'),
       array('system', 'drupalSettings'),
       array('system', 'drupal.progress'),
+      array('system', 'drupal.message'),
       array('system', 'jquery.once'),
     ),
   );
@@ -986,6 +987,19 @@ function system_library_info() {
     ),
   );
 
+  // Drupal's message utility.
+  $libraries['drupal.message'] = array(
+    'title' => 'Drupal message',
+    'version' => \Drupal::VERSION,
+    'js' => array(
+      'core/misc/message.js' => array('group' => JS_LIBRARY),
+    ),
+    'dependencies' => array(
+      array('system', 'drupal'),
+      array('system', 'drupal.debounce'),
+    ),
+  );
+  
   // Drupal's dialog component.
   $libraries['drupal.dialog'] = array(
     'title' => 'Drupal Dialog',
diff --git a/core/modules/system/templates/page.html.twig b/core/modules/system/templates/page.html.twig
index 1f6f916..eff4d20 100644
--- a/core/modules/system/templates/page.html.twig
+++ b/core/modules/system/templates/page.html.twig
@@ -104,7 +104,7 @@
 
   {{ breadcrumb }}
 
-  {{ messages }}
+  <div data-drupal-messages>{{ messages }}</div>
 
   {{ page.help }}
 
diff --git a/core/themes/bartik/templates/page.html.twig b/core/themes/bartik/templates/page.html.twig
index 5602997..1545fb1 100644
--- a/core/themes/bartik/templates/page.html.twig
+++ b/core/themes/bartik/templates/page.html.twig
@@ -128,11 +128,9 @@
     {% endif %}
   </div></header> <!-- /.section, /#header-->
 
-  {% if messages %}
-    <div id="messages"><div class="section clearfix">
-      {{ messages }}
-    </div></div> <!-- /.section, /#messages -->
-  {% endif %}
+  <div id="messages"><div class="section clearfix" data-drupal-messages>
+    {{ messages }}
+  </div></div> <!-- /.section, /#messages -->
 
   {% if page.featured %}
     <aside id="featured"><div class="section clearfix">
diff --git a/core/themes/seven/templates/page.html.twig b/core/themes/seven/templates/page.html.twig
index 5a50431..40f5114 100644
--- a/core/themes/seven/templates/page.html.twig
+++ b/core/themes/seven/templates/page.html.twig
@@ -84,9 +84,7 @@
 
     <main id="content" class="clearfix" role="main">
       <div class="visually-hidden"><a id="main-content"></a></div>
-      {% if messages %}
-        <div id="console" class="clearfix">{{ messages }}</div>
-      {% endif %}
+      <div id="console" class="clearfix" data-drupal-messages>{{ messages }}</div>
       {% if page.help %}
         <div id="help">
           {{ page.help }}
