diff --git a/animatecss.info.yml b/animatecss.info.yml
index 70a0c5d..15f8522 100644
--- a/animatecss.info.yml
+++ b/animatecss.info.yml
@@ -1,5 +1,5 @@
 name: 'AnimateCSS'
 type: module
 description: 'Integrates Animate.css, is a library of ready-to-use, cross-browser animations for use in your web projects.'
-core_version_requirement: ^8.8 || ^9 || ^10 || ^11
+core_version_requirement: ^11.1 || ^12
 package: Animate CSS
diff --git a/animatecss.install b/animatecss.install
index 05b5bae..9ea5c17 100644
--- a/animatecss.install
+++ b/animatecss.install
@@ -1,5 +1,12 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Component\Utility\DeprecationHelper;
+use Drupal\Core\Extension\Requirement\RequirementSeverity;
+
 /**
  * @file
  * Install, update, uninstall Requirements functions for the AnimateCSS module.
@@ -18,7 +25,7 @@ function animatecss_requirements($phase) {
   $requirements = [];
 
   // Check Animate.css library is existing.
-  /** @var Drupal\Core\Asset\LibraryDiscovery $library_discovery */
+  /** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
   $library_discovery = \Drupal::service('library.discovery');
   $library_animate = $library_discovery->getLibraryByName('animatecss', 'animate.css');
   $library_exists = FALSE;
@@ -50,7 +57,7 @@ function animatecss_requirements($phase) {
   $requirements['animatecss'] = [
     'title'       => t('Animate.css library'),
     'value'       => $library_exists ? t('Installed') : t('Not installed'),
-    'severity'    => $library_exists ? REQUIREMENT_OK : REQUIREMENT_ERROR,
+    'severity'    => $library_exists ? DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2.0', fn() => RequirementSeverity::OK, fn() => REQUIREMENT_OK) : DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2.0', fn() => RequirementSeverity::Error, fn() => REQUIREMENT_ERROR),
     'description' => $description,
   ];
 
diff --git a/animatecss.module b/animatecss.module
index 885408b..5341cb7 100644
--- a/animatecss.module
+++ b/animatecss.module
@@ -15,33 +15,16 @@
  * Copyright (C) 2021-2023 Daniel Eden
  */
 
-use Drupal\Core\Installer\InstallerKernel;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\animatecss\Hook\AnimatecssHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function animatecss_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.animatecss':
-      $output  = '<h3 class="animate__animated animate__bounce">' . t('About') . '</h3>';
-      $output .= '<p class="animate__animated animate__fadeInUp animate__delay-1s">' . t('The AnimateCSS is a module that aims to integrate <a href=":animate_library">Animate.css</a> library with Drupal. Animate.css is a library of ready-to-use, cross-browser animations for use in your web projects. Great for emphasis, home pages, sliders, and attention-guiding hints. AnimateCSS module allows you to quickly attach Animate.css library in your page.', [':animate_library' => 'https://animate.style/']) . '</p>';
-      $output .= '<h3 class="animate__animated animate__zoomIn animate__delay-2s">' . t('Uses') . '</h3>';
-      $output .= '<dl>';
-      $output .= '<dt class="animate__animated animate__flipInX animate__delay-3s">' . t('Basic usage') . '</dt>';
-      $output .= '<dd class="animate__animated animate__slideInLeft animate__delay-4s"><p>' . t('Add the class animate__animated to an element, along with any of the animation names (do not forget the animate__ prefix!)') . '</p>';
-      $output .= '<pre><code>';
-      $output .= '&lt;h1 class="animate__animated animate__bounce"&gt;An animated element&lt;/h1&gt;' . "\n";
-      $output .= '</code></pre></dd>';
-      $output .= '<dt class="animate__animated animate__flipInX animate__delay-3s">' . t('Usage with Javascript') . '</dt>';
-      $output .= '<dd class="animate__animated animate__slideInRight animate__delay-4s"><p>' . t('You can do a whole bunch of other stuff with animate.css when you combine it with Javascript.') . '</p>';
-      $output .= '<pre>';
-      $output .= "const element = document.querySelector('.my-element');" . "\n";
-      $output .= "element.classList.add('animate__animated', 'animate__bounceOutLeft');";
-      $output .= '</pre></dd>';
-      $output .= '</dl>';
-      return $output;
-  }
+  return \Drupal::service(AnimatecssHooks::class)->help($route_name, $route_match);
 }
 
 /**
@@ -52,7 +35,7 @@ function animatecss_help($route_name, RouteMatchInterface $route_match) {
  */
 function animatecss_check_installed() {
   // Throw error if Animate.css library file not found.
-  /** @var Drupal\Core\Asset\LibraryDiscovery $library_discovery */
+  /** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
   $library_discovery = \Drupal::service('library.discovery');
   $library_exists = FALSE;
   $definition = $library_discovery->getLibraryByName('animatecss', 'animate.css');
@@ -68,24 +51,9 @@ function animatecss_check_installed() {
 /**
  * Implements hook_page_attachments().
  */
+#[LegacyHook]
 function animatecss_page_attachments(array &$attachments) {
-  // Don't add the Library during installation.
-  if (InstallerKernel::installationAttempted()) {
-    return;
-  }
-
-  // Check first AnimateCSS UI module is not installed and library not exists.
-  $moduleHandler = \Drupal::service('module_handler');
-  if (!$moduleHandler->moduleExists('animatecss_ui')) {
-    // Check if Animate.css library not exist in local library then
-    // attach the latest version of Animate.css automatically from CDN.
-    if (animatecss_check_installed()) {
-      $attachments['#attached']['library'][] = 'animatecss/animate.css';
-    }
-    else {
-      $attachments['#attached']['library'][] = 'animatecss/animate.cdn';
-    }
-  }
+  \Drupal::service(AnimatecssHooks::class)->pageAttachments($attachments);
 }
 
 /**
diff --git a/animatecss.services.yml b/animatecss.services.yml
new file mode 100644
index 0000000..5308423
--- /dev/null
+++ b/animatecss.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\animatecss\Hook\AnimatecssHooks:
+    class: Drupal\animatecss\Hook\AnimatecssHooks
+    autowire: true
diff --git a/animatecss_ui/animatecss_ui.info.yml b/animatecss_ui/animatecss_ui.info.yml
index dc10ee1..0520951 100644
--- a/animatecss_ui/animatecss_ui.info.yml
+++ b/animatecss_ui/animatecss_ui.info.yml
@@ -1,7 +1,7 @@
 name: 'AnimateCSS UI'
 type: module
 description: 'Animate.css library configuration UI.'
-core_version_requirement: ^8.8 || ^9 || ^10 || ^11
+core_version_requirement: ^11.1 || ^12
 package: Animate CSS
 configure: animatecss.admin
 dependencies:
diff --git a/animatecss_ui/animatecss_ui.install b/animatecss_ui/animatecss_ui.install
index fbae9c4..1bf623d 100644
--- a/animatecss_ui/animatecss_ui.install
+++ b/animatecss_ui/animatecss_ui.install
@@ -5,6 +5,7 @@
  * Install, update and uninstall functions for the AnimateCSS module.
  */
 
+use Drupal\Component\Utility\DeprecationHelper;
 use Drupal\Core\Url;
 
 /**
@@ -147,7 +148,7 @@ function animatecss_ui_update_8003() {
   $config = $config_factory->getEditable('animatecss.settings');
   // Add new silent configuration field.
   $config->set('silent', FALSE);
-  $config->save(TRUE);
+  DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
 }
 
 /**
@@ -171,7 +172,7 @@ function animatecss_ui_update_8005() {
   if ($config->get('options.clean') === NULL) {
     // Set the default value for the 'clean' option.
     $config->set('options.clean', FALSE);
-    $config->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
   }
 }
 
@@ -187,20 +188,20 @@ function animatecss_ui_update_8006() {
   if ($config->get('options.event') === NULL) {
     // Set the default value for the 'event' option.
     $config->set('options.event', 'onload');
-    $config->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
   }
 
   // Check if the 'once' option already exists to avoid overwriting it.
   if ($config->get('options.once') === NULL) {
     // Set the default value for the 'once' option.
     $config->set('options.once', FALSE);
-    $config->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
   }
 
   // Check if the 'display' option already exists to avoid overwriting it.
   if ($config->get('options.display') === NULL) {
     // Set the default value for the 'display' option.
     $config->set('options.display', FALSE);
-    $config->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
   }
 }
diff --git a/animatecss_ui/animatecss_ui.module b/animatecss_ui/animatecss_ui.module
index def68e4..f6b88ac 100644
--- a/animatecss_ui/animatecss_ui.module
+++ b/animatecss_ui/animatecss_ui.module
@@ -15,175 +15,26 @@
  * Copyright (C) 2021-2023 Daniel Eden
  */
 
-use Drupal\Core\Installer\InstallerKernel;
-use Drupal\Core\Link;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\animatecss_ui\Hook\AnimatecssUiHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function animatecss_ui_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.animatecss_ui':
-      return '<p>' . t('<a href=":animate_url">Animate.css</a> is a library of ready-to-use, cross-browser animations for use in your web projects. Great for emphasis, home pages, sliders, and attention-guiding hints., see the <a href=":animate_github">Animate.css Github</a> for usage and Configure on <a href=":animate_config">AnimateCSS module settings</a> to put CSS selectors you want animated element.', [
-        ':animate_url'    => 'https://animate.style/',
-        ':animate_github' => 'https://github.com/animate-css/animate.css',
-        ':animate_config' => Link::createFromRoute(t('admin page'), 'animatecss.settings')->toString(),
-      ]) . '</p>';
-  }
+  return \Drupal::service(AnimatecssUiHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_page_attachments().
  */
+#[LegacyHook]
 function animatecss_ui_page_attachments(array &$attachments) {
-  // Don't add the library during installation.
-  if (InstallerKernel::installationAttempted()) {
-    return;
-  }
-
-  // Load the Animate.css configuration settings.
-  $config = \Drupal::config('animatecss.settings');
-
-  // Attach Animate.css to pages with chosen method.
-  $method = animatecss_check_installed() ? $config->get('method') : 'cdn';
-  $compat = $config->get('compat');
-
-  // Checking the path to load Animate.css for demo examples,
-  // It's just in Animatecss configuration.
-  $currentPath = Url::fromRoute('<current>')->toString();
-  $settingPath = Url::fromRoute('animatecss.admin')->toString() . '/*';
-
-  if (\Drupal::service('path.matcher')->matchPath($currentPath, $settingPath)) {
-    $options = $config->get('options');
-    $options['selector'] = '.animate__sample';
-
-    // Attach Animate.css for examples.
-    $attachments['#attached']['drupalSettings']['animatecss']['sample'] = $options;
-    $attachments['#attached']['drupalSettings']['animatecss']['compat'] = $compat;
-
-    if ($method == 'cdn') {
-      $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-dev';
-    }
-    else {
-      $attachments['#attached']['library'][] = 'animatecss_ui/animate-dev';
-    }
-    return;
-  }
-
-  // Don't include Animate.css library if the user has opted out of loading it.
-  if (!$config->get('load')) {
-    return TRUE;
-  }
-
-  // Don't add the Animate.css on specified paths.
-  if (!_animatecss_ui_check_url()) {
-    return TRUE;
-  }
-
-  // Check for load development and production version.
-  $variant_options = ['source', 'minified'];
-  $variant = $variant_options[$config->get('minimized.options')];
-  if ($method == 'cdn') {
-    // The Animate.css library is attached with the CDN method.
-    // However, if the compatible version was enabled,
-    // the compatible version of the CDN should be added.
-    if ($compat) {
-      $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-compat';
-    }
-    else {
-      // Check variant to load Animate.css from CDN.
-      switch ($variant) {
-        case 'minified':
-          $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn';
-          break;
-
-        case 'source':
-          $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-dev';
-          break;
-      }
-    }
-  }
-  else {
-    // If the compatible version is enabled in the settings,
-    // it will include the compatible version of the Animate.css library.
-    // Because the compatible version is only available in compressed form.
-    if ($compat) {
-      $attachments['#attached']['library'][] = 'animatecss_ui/animate-compat';
-    }
-    else {
-      // Check variant to load Animate.css from local.
-      switch ($variant) {
-        case 'minified':
-          $attachments['#attached']['library'][] = 'animatecss_ui/animate-css';
-          break;
-
-        case 'source':
-          $attachments['#attached']['library'][] = 'animatecss_ui/animate-dev';
-          break;
-      }
-    }
-  }
-
-  // Get selectors from config.
-  $options = $config->get('options');
-  $animated = [];
-
-  // Load enabled animate selectors from database.
-  $results = \Drupal::service('animatecss.animate_manager')->loadAnimate()->fetchAll();
-  if (count($results)) {
-    $selectors = [];
-    foreach ($results as $animate) {
-      $animate_options = unserialize($animate->options, ['allowed_classes' => FALSE]);
-
-      // Support WOW JS Module.
-      if (isset($animate_options['wow']) && $animate_options['wow']['enable']) {
-        continue;
-      }
-
-      // Support AOS JS Module.
-      if (isset($animate_options['aos']) && $animate_options['aos']['enable']) {
-        continue;
-      }
-
-      $selectors[] = $animate->selector;
-      $animated[$animate->aid] = ['selector' => $animate->selector] + $animate_options;
-    }
-
-    // Merge global selectors from config with database selectors.
-    if (count(array_filter($config->get('options.selector'))) && count($selectors)) {
-      $options['selector'] = array_diff($options['selector'], $selectors);
-
-      // Attach config selectors after merge if there were any left.
-      if (count($options['selector'])) {
-        array_unshift($animated, $options);
-      }
-    }
-  }
-  else {
-    // If global selectors are set, get the selectors from the configuration.
-    if (count($config->get('options.selector'))) {
-      $animated = [$options];
-    }
-  }
-
-  // If there is animate selectors, then the init file
-  // with options will be added to the page.
-  if (count($animated)) {
-    // Export settings.
-    $attachments['#attached']['drupalSettings']['animatecss']['elements'] = $animated;
-
-    // If set compatible mode, pass to settings for change class in javascript.
-    if ($compat) {
-      $attachments['#attached']['drupalSettings']['animatecss']['compat'] = $compat;
-    }
-
-    // Init animate.
-    $attachments['#attached']['library'][] = 'animatecss_ui/animate-init';
-  }
+  return \Drupal::service(AnimatecssUiHooks::class)->pageAttachments($attachments);
 }
 
 /**
@@ -197,7 +48,7 @@ function animatecss_ui_page_attachments(array &$attachments) {
  * @return bool
  *   TRUE if Animate.css should be active for the current page.
  */
-function _animatecss_ui_check_url(Request $request = NULL, RequestStack $request_stack = NULL) {
+function _animatecss_ui_check_url(?Request $request = NULL, ?RequestStack $request_stack = NULL) {
   if (!isset($request)) {
     $request = \Drupal::request();
   }
diff --git a/animatecss_ui/animatecss_ui.services.yml b/animatecss_ui/animatecss_ui.services.yml
index fc34db9..d89a4b3 100644
--- a/animatecss_ui/animatecss_ui.services.yml
+++ b/animatecss_ui/animatecss_ui.services.yml
@@ -4,3 +4,7 @@ services:
     arguments: [ '@database' ]
     tags:
       - { name: backend_overridable }
+
+  Drupal\animatecss_ui\Hook\AnimatecssUiHooks:
+    class: Drupal\animatecss_ui\Hook\AnimatecssUiHooks
+    autowire: true
diff --git a/animatecss_ui/src/Hook/AnimatecssUiHooks.php b/animatecss_ui/src/Hook/AnimatecssUiHooks.php
new file mode 100644
index 0000000..3cadace
--- /dev/null
+++ b/animatecss_ui/src/Hook/AnimatecssUiHooks.php
@@ -0,0 +1,166 @@
+<?php
+
+namespace Drupal\animatecss_ui\Hook;
+
+use Drupal\Core\Url;
+use Drupal\Core\Installer\InstallerKernel;
+use Drupal\Core\Link;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for animatecss_ui.
+ */
+class AnimatecssUiHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.animatecss_ui':
+        return '<p>' . $this->t('<a href=":animate_url">Animate.css</a> is a library of ready-to-use, cross-browser animations for use in your web projects. Great for emphasis, home pages, sliders, and attention-guiding hints., see the <a href=":animate_github">Animate.css Github</a> for usage and Configure on <a href=":animate_config">AnimateCSS module settings</a> to put CSS selectors you want animated element.', [
+          ':animate_url' => 'https://animate.style/',
+          ':animate_github' => 'https://github.com/animate-css/animate.css',
+          ':animate_config' => Link::createFromRoute($this->t('admin page'), 'animatecss.settings')->toString(),
+        ]) . '</p>';
+    }
+  }
+
+  /**
+   * Implements hook_page_attachments().
+   */
+  #[Hook('page_attachments')]
+  public static function pageAttachments(array &$attachments) {
+    // Don't add the library during installation.
+    if (InstallerKernel::installationAttempted()) {
+      return;
+    }
+    // Load the Animate.css configuration settings.
+    $config = \Drupal::config('animatecss.settings');
+    // Attach Animate.css to pages with chosen method.
+    $method = animatecss_check_installed() ? $config->get('method') : 'cdn';
+    $compat = $config->get('compat');
+    // Checking the path to load Animate.css for demo examples,
+    // It's just in Animatecss configuration.
+    $currentPath = Url::fromRoute('<current>')->toString();
+    $settingPath = Url::fromRoute('animatecss.admin')->toString() . '/*';
+    if (\Drupal::service('path.matcher')->matchPath($currentPath, $settingPath)) {
+      $options = $config->get('options');
+      $options['selector'] = '.animate__sample';
+      // Attach Animate.css for examples.
+      $attachments['#attached']['drupalSettings']['animatecss']['sample'] = $options;
+      $attachments['#attached']['drupalSettings']['animatecss']['compat'] = $compat;
+      if ($method == 'cdn') {
+        $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-dev';
+      }
+      else {
+        $attachments['#attached']['library'][] = 'animatecss_ui/animate-dev';
+      }
+      return;
+    }
+    // Don't include Animate.css library if the user has opted out of loading it.
+    if (!$config->get('load')) {
+      return TRUE;
+    }
+    // Don't add the Animate.css on specified paths.
+    if (!_animatecss_ui_check_url()) {
+      return TRUE;
+    }
+    // Check for load development and production version.
+    $variant_options = [
+      'source',
+      'minified',
+    ];
+    $variant = $variant_options[$config->get('minimized.options')];
+    if ($method == 'cdn') {
+      // The Animate.css library is attached with the CDN method.
+      // However, if the compatible version was enabled,
+      // the compatible version of the CDN should be added.
+      if ($compat) {
+        $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-compat';
+      }
+      else {
+        // Check variant to load Animate.css from CDN.
+        switch ($variant) {
+          case 'minified':
+            $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn';
+            break;
+
+          case 'source':
+            $attachments['#attached']['library'][] = 'animatecss_ui/animate-cdn-dev';
+            break;
+        }
+      }
+    }
+    elseif ($compat) {
+      $attachments['#attached']['library'][] = 'animatecss_ui/animate-compat';
+    }
+    else {
+      // Check variant to load Animate.css from local.
+      switch ($variant) {
+        case 'minified':
+          $attachments['#attached']['library'][] = 'animatecss_ui/animate-css';
+          break;
+
+        case 'source':
+          $attachments['#attached']['library'][] = 'animatecss_ui/animate-dev';
+          break;
+      }
+    }
+    // Get selectors from config.
+    $options = $config->get('options');
+    $animated = [];
+    // Load enabled animate selectors from database.
+    $results = \Drupal::service('animatecss.animate_manager')->loadAnimate()->fetchAll();
+    if (count($results)) {
+      $selectors = [];
+      foreach ($results as $animate) {
+        $animate_options = unserialize($animate->options, [
+          'allowed_classes' => FALSE,
+        ]);
+        // Support WOW JS Module.
+        if (isset($animate_options['wow']) && $animate_options['wow']['enable']) {
+          continue;
+        }
+        // Support AOS JS Module.
+        if (isset($animate_options['aos']) && $animate_options['aos']['enable']) {
+          continue;
+        }
+        $selectors[] = $animate->selector;
+        $animated[$animate->aid] = [
+          'selector' => $animate->selector,
+        ] + $animate_options;
+      }
+      // Merge global selectors from config with database selectors.
+      if (count(array_filter($config->get('options.selector'))) && count($selectors)) {
+        $options['selector'] = array_diff($options['selector'], $selectors);
+        // Attach config selectors after merge if there were any left.
+        if (count($options['selector'])) {
+          array_unshift($animated, $options);
+        }
+      }
+    }
+    elseif (count($config->get('options.selector'))) {
+      $animated = [
+        $options,
+      ];
+    }
+    // If there is animate selectors, then the init file
+    // with options will be added to the page.
+    if (count($animated)) {
+      // Export settings.
+      $attachments['#attached']['drupalSettings']['animatecss']['elements'] = $animated;
+      // If set compatible mode, pass to settings for change class in javascript.
+      if ($compat) {
+        $attachments['#attached']['drupalSettings']['animatecss']['compat'] = $compat;
+      }
+      // Init animate.
+      $attachments['#attached']['library'][] = 'animatecss_ui/animate-init';
+    }
+  }
+
+}
diff --git a/composer.json b/composer.json
index 4e4464a..d65090b 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,7 @@
     },
     "minimum-stability": "dev",
     "require": {
-        "drupal/core": "^8.8 || ^9 || ^10 || ^11"
+        "drupal/core": "^11.1 || ^12"
     },
     "autoload": {
         "psr-4": {
diff --git a/src/Hook/AnimatecssHooks.php b/src/Hook/AnimatecssHooks.php
new file mode 100644
index 0000000..66f994c
--- /dev/null
+++ b/src/Hook/AnimatecssHooks.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\animatecss\Hook;
+
+use Drupal\Core\Installer\InstallerKernel;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for animatecss.
+ */
+class AnimatecssHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.animatecss':
+        $output = '<h3 class="animate__animated animate__bounce">' . $this->t('About') . '</h3>';
+        $output .= '<p class="animate__animated animate__fadeInUp animate__delay-1s">' . $this->t('The AnimateCSS is a module that aims to integrate <a href=":animate_library">Animate.css</a> library with Drupal. Animate.css is a library of ready-to-use, cross-browser animations for use in your web projects. Great for emphasis, home pages, sliders, and attention-guiding hints. AnimateCSS module allows you to quickly attach Animate.css library in your page.', [
+          ':animate_library' => 'https://animate.style/',
+        ]) . '</p>';
+        $output .= '<h3 class="animate__animated animate__zoomIn animate__delay-2s">' . $this->t('Uses') . '</h3>';
+        $output .= '<dl>';
+        $output .= '<dt class="animate__animated animate__flipInX animate__delay-3s">' . $this->t('Basic usage') . '</dt>';
+        $output .= '<dd class="animate__animated animate__slideInLeft animate__delay-4s"><p>' . $this->t('Add the class animate__animated to an element, along with any of the animation names (do not forget the animate__ prefix!)') . '</p>';
+        $output .= '<pre><code>';
+        $output .= '&lt;h1 class="animate__animated animate__bounce"&gt;An animated element&lt;/h1&gt;' . "\n";
+        $output .= '</code></pre></dd>';
+        $output .= '<dt class="animate__animated animate__flipInX animate__delay-3s">' . $this->t('Usage with Javascript') . '</dt>';
+        $output .= '<dd class="animate__animated animate__slideInRight animate__delay-4s"><p>' . $this->t('You can do a whole bunch of other stuff with animate.css when you combine it with Javascript.') . '</p>';
+        $output .= '<pre>';
+        $output .= "const element = document.querySelector('.my-element');" . "\n";
+        $output .= "element.classList.add('animate__animated', 'animate__bounceOutLeft');";
+        $output .= '</pre></dd>';
+        $output .= '</dl>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_page_attachments().
+   */
+  #[Hook('page_attachments')]
+  public static function pageAttachments(array &$attachments) {
+    // Don't add the Library during installation.
+    if (InstallerKernel::installationAttempted()) {
+      return;
+    }
+    // Check first AnimateCSS UI module is not installed and library not exists.
+    $moduleHandler = \Drupal::service('module_handler');
+    if (!$moduleHandler->moduleExists('animatecss_ui')) {
+      // Check if Animate.css library not exist in local library then
+      // attach the latest version of Animate.css automatically from CDN.
+      if (animatecss_check_installed()) {
+        $attachments['#attached']['library'][] = 'animatecss/animate.css';
+      }
+      else {
+        $attachments['#attached']['library'][] = 'animatecss/animate.cdn';
+      }
+    }
+  }
+
+}
