diff --git a/js/messages.js b/js/messages.js
new file mode 100644
index 0000000000000000000000000000000000000000..5733415d3d26dcb3eab5fd082b3a5faac565d3f8
--- /dev/null
+++ b/js/messages.js
@@ -0,0 +1,70 @@
+/**
+ * @file
+ * Message template overrides.
+ */
+
+((Drupal) => {
+  /**
+   * Overrides message theme function.
+   *
+   * @param {object} message
+   *   The message object.
+   * @param {string} message.text
+   *   The message text.
+   * @param {object} options
+   *   The message context.
+   * @param {string} options.type
+   *   The message type.
+   * @param {string} options.id
+   *   ID of the message, for reference.
+   *
+   * @return {HTMLElement}
+   *   A DOM Node.
+   */
+  Drupal.theme.message = ({ text }, { type, id }) => {
+    const types = {
+      default: 'info',
+      info: 'info',
+      message: 'info',
+      status: 'success',
+      success: 'success',
+      warning: 'warning',
+      error: 'danger',
+    };
+
+    const typeName = types[type] || 'info';
+    const typeLabel = `${type}-alert-title`;
+    const messagesTypes = Drupal.Message.getMessageTypeLabels();
+    const messageWrapper = document.createElement('div');
+
+    messageWrapper.setAttribute(
+      'role',
+      type === 'error' ? 'alert' : 'contentinfo',
+    );
+    messageWrapper.setAttribute(
+      'class',
+      `rvt-alert rvt-alert--${typeName} [ rvt-m-tb-md ]`,
+    );
+    messageWrapper.setAttribute('aria-labelledby', typeLabel);
+    messageWrapper.setAttribute('data-rvt-alert', typeName);
+    messageWrapper.setAttribute('data-drupal-message-id', id);
+    messageWrapper.setAttribute('data-drupal-message-type', type);
+
+    messageWrapper.innerHTML = `
+      <h2 id="${typeLabel}" class="rvt-alert__title rvt-sr-only">
+        ${messagesTypes[type]}
+      </h2>
+      <div class="rvt-alert__message">
+        ${text}
+      </div>
+      <button class="rvt-alert__dismiss" data-rvt-alert-close>
+        <span class="rvt-sr-only">Dismiss this alert</span>
+        <svg fill="currentColor" width="16" height="16" viewBox="0 0 16 16">
+          <path d="m3.5 2.086 4.5 4.5 4.5-4.5L13.914 3.5 9.414 8l4.5 4.5-1.414 1.414-4.5-4.5-4.5 4.5L2.086 12.5l4.5-4.5-4.5-4.5L3.5 2.086Z"></path>
+        </svg>
+      </button>
+    `;
+
+    return messageWrapper;
+  };
+})(Drupal);
diff --git a/rivet.info.yml b/rivet.info.yml
index 443329bf0681a200fc1dd2d0394894249030989e..02d5731fd257d6f5d38e917d181be5b9e6be234f 100644
--- a/rivet.info.yml
+++ b/rivet.info.yml
@@ -20,6 +20,8 @@ libraries-extend:
     - rivet/dialog
   file/drupal.file:
     - rivet/file
+  core/drupal.message:
+    - rivet/messages
   core/drupal.progress:
     - rivet/progress
   block/drupal.block.admin:
diff --git a/rivet.libraries.yml b/rivet.libraries.yml
index 9071a51eda00229c39101a7c0763a9a30d8a5eb8..0180e8720171d061ce2e569dfd0518241856014d 100644
--- a/rivet.libraries.yml
+++ b/rivet.libraries.yml
@@ -112,6 +112,9 @@ messages:
     theme:
       css/components/messages.css:
         weight: -10
+  js:
+    js/messages.js: {}
+
 node:
   version: VERSION
   css:
diff --git a/rivet.theme b/rivet.theme
index 6c4f8b9cdd9a85a1cf86ca634f02b1d5b5596a22..c699c5c652eddc85f779f88b27be8d8f8344bf87 100644
--- a/rivet.theme
+++ b/rivet.theme
@@ -165,17 +165,13 @@ function _rivet_page_status(): array {
 function rivet_preprocess_page(array &$variables): void {
   // Uncomment these lines to theme Status messages.
   // @codingStandardsIgnoreStart
-  # $default = t('This is a default message <a href="#">with link</a>.');
-  # $info = t('This is an info message <a href="#">with link</a>.');
   # $error = t('This is an error message <a href="#">with link</a>.');
   # $warning = t('This is a warning message <a href="#">with link</a>.');
   # $status = t('This is a successful message <a href="#">with link</a>.');
   # $lorem = t('Lorem ipsum dolor sit amet.');
-  # \Drupal::messenger()->addMessage($default, 'default');
-  # \Drupal::messenger()->addMessage($info, 'info');
-  # \Drupal::messenger()->addError($error);
-  # \Drupal::messenger()->addWarning($warning);
-  # \Drupal::messenger()->addStatus($status);
+  # \Drupal::messenger()->addMessage($error, 'error');
+  # \Drupal::messenger()->addMessage($warning, 'warning');
+  # \Drupal::messenger()->addMessage($status);
   # \Drupal::messenger()->addStatus(str_repeat($lorem . ' ', 6));
   // @codingStandardsIgnoreEnd
   $variables['page_status'] = _rivet_page_status();
diff --git a/templates/misc/status-messages.html.twig b/templates/misc/status-messages.html.twig
index d465eda0e46618b0ba11f35e8e57bda64ccde10d..e00e5fb49d8ed3daf00bc676aad7e15ff4be40ad 100644
--- a/templates/misc/status-messages.html.twig
+++ b/templates/misc/status-messages.html.twig
@@ -30,7 +30,7 @@
     'error' : 'danger',
   }
 %}
-<div data-drupal-messages>
+<div data-drupal-messages><div class="messages__wrapper">
 {% block messages %}
 {% for type, messages in message_list %}
   {% set type_name = types[type] ?? 'info' %}
@@ -67,4 +67,4 @@
   {% set attributes = attributes.removeClass(classes) %}
 {% endfor %}
 {% endblock messages %}
-</div>
+</div></div>