diff --git a/admin_toolbar.install b/admin_toolbar.install
index 35e9a67..f9262bd 100644
--- a/admin_toolbar.install
+++ b/admin_toolbar.install
@@ -1,5 +1,11 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Component\Utility\DeprecationHelper;
+
 /**
  * @file
  * Install, update and uninstall functions for the Admin Toolbar module.
@@ -25,7 +31,7 @@ function admin_toolbar_update_8002() {
   $config = $config_factory->getEditable('admin_toolbar.settings');
   if (empty($config->get('menu_depth'))) {
     $config->set('menu_depth', 4);
-    $config->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $config->save(), fn() => $config->save(TRUE));
   }
 }
 
@@ -65,8 +71,8 @@ function admin_toolbar_update_8004() {
     $hoverintent_behavior_config_default['enabled'] = $hoverintent_functionality;
     // Remove the 'hoverintent_functionality' configuration from the
     // 'admin_toolbar_tools.settings'.
-    $admin_toolbar_tools_config->clear('hoverintent_functionality')
-      ->save(TRUE);
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $admin_toolbar_tools_config->clear('hoverintent_functionality')->save(), fn() => $admin_toolbar_tools_config->clear('hoverintent_functionality')
+      ->save(TRUE));
   }
 
   // If the admin_toolbar_tools config is new, it means that the module was
diff --git a/admin_toolbar.module b/admin_toolbar.module
index c89a2c8..07fae30 100644
--- a/admin_toolbar.module
+++ b/admin_toolbar.module
@@ -7,71 +7,25 @@
 
 declare(strict_types=1);
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\admin_toolbar\Hook\AdminToolbarHooks;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Url;
-use Drupal\admin_toolbar\Render\Element\AdminToolbar;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function admin_toolbar_help($route_name) {
-  switch ($route_name) {
-    case 'help.page.admin_toolbar':
-      $variables = [
-        ':toolbar' => Url::fromRoute('help.page', ['name' => 'toolbar'])->toString(),
-        ':automated_cron' => (\Drupal::moduleHandler()->moduleExists('automated_cron')) ? Url::fromRoute('help.page', ['name' => 'automated_cron'])->toString() : '#',
-      ];
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Admin Toolbar module enhances the <a href=":toolbar">Toolbar</a> module by providing fast access to all the administrative links at the top of your site. Admin Toolbar remains a very "lightweight" module by closely integrating with all Toolbar functionality. It can be used in conjunction with all the sub modules included on Admin Toolbar, for quick access to system commands such as Flush all caches, <a href=":automated_cron">Run cron</a>, Run Updates, etc.', $variables) . '</p>';
-      $output .= '<h3>' . t('Uses') . '</h3>';
-      $output .= '<p>' . t('The Admin Toolbar greatly improves the user experience for those who regularly interact with the site Toolbar by providing fast, full access to all links in the site Toolbar without having to click to get there.') . '</p>';
-      return $output;
-  }
+  return \Drupal::service(AdminToolbarHooks::class)->help($route_name);
 }
 
 /**
  * Implements hook_toolbar_alter().
  */
+#[LegacyHook]
 function admin_toolbar_toolbar_alter(&$items) {
-  $items['administration']['tray']['toolbar_administration']['#pre_render'] = [
-    [AdminToolbar::class, 'preRenderTray'],
-  ];
-  $admin_toolbar_config = \Drupal::config('admin_toolbar.settings');
-  $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree';
-
-  // Add sticky behavior libraries based on the configuration.
-  $sticky_behavior = $admin_toolbar_config->get('sticky_behavior') ?? 'enabled';
-  switch ($sticky_behavior) {
-    case 'disabled':
-      $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.disable_sticky';
-      break;
-
-    case 'hide_on_scroll_down':
-      $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.sticky_behavior';
-      break;
-
-    default:
-      break;
-  }
-  // Add the hoverIntent behavior library if enabled.
-  $hoverintent_behavior = $admin_toolbar_config->get('hoverintent_behavior');
-  if (!empty($hoverintent_behavior['enabled'])) {
-    // Use the hoverIntent plugin library.
-    $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree.hoverintent';
-    // Add the configured hoverIntent settings values to the JS of the toolbar.
-    $items['administration']['#attached']['drupalSettings']['hoverIntentTimeout'] = $hoverintent_behavior['timeout'];
-  }
-  else {
-    // Use default Admin Toolbar hover library.
-    $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree.hover';
-  }
-
-  // Add the toggle toolbar keyboard shortcut library if enabled.
-  if ($admin_toolbar_config->get('enable_toggle_shortcut')) {
-    $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.toggle_shortcut';
-  }
+  \Drupal::service(AdminToolbarHooks::class)->toolbarAlter($items);
 }
 
 /**
diff --git a/admin_toolbar.services.yml b/admin_toolbar.services.yml
new file mode 100644
index 0000000..3758f5e
--- /dev/null
+++ b/admin_toolbar.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\admin_toolbar\Hook\AdminToolbarHooks:
+    class: Drupal\admin_toolbar\Hook\AdminToolbarHooks
+    autowire: true
diff --git a/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.install b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.install
index 42bc764..7996666 100644
--- a/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.install
+++ b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.install
@@ -1,5 +1,12 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Component\Utility\DeprecationHelper;
+use Drupal\Core\Extension\Requirement\RequirementSeverity;
+
 /**
  * @file
  * Install/uninstall or update functions for Admin Toolbar Links Access Filter.
@@ -23,7 +30,7 @@ See issues: <a href=":issue_url1">#3463291</a> and <a href=":issue_url2">#348724
           ':issue_url1' => 'https://www.drupal.org/node/3463291',
           ':issue_url2' => 'https://www.drupal.org/node/3487246',
         ]),
-        'severity' => REQUIREMENT_ERROR,
+        'severity' => DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2.0', fn() => RequirementSeverity::Error, fn() => REQUIREMENT_ERROR),
       ];
     }
   }
diff --git a/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module
index f6cc614..36a6c44 100644
--- a/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module
+++ b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module
@@ -5,6 +5,8 @@
  * This module don't show menu links that you don't have access permission for.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\admin_toolbar_links_access_filter\Hook\AdminToolbarLinksAccessFilterHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\Entity\Role;
@@ -13,16 +15,9 @@ use Symfony\Component\Routing\Exception\RouteNotFoundException;
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function admin_toolbar_links_access_filter_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    // Main module help.
-    case 'help.page.admin_toolbar_links_access_filter':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Admin Toolbar Links Access Filter module provides a workaround for the common problem that users with <em>Use the administration pages and help</em> permission see menu links they done not have access permission for.') . '</p>';
-
-      return $output;
-  }
+  return \Drupal::service(AdminToolbarLinksAccessFilterHooks::class)->help($route_name, $route_match);
 }
 
 /**
@@ -30,28 +25,9 @@ function admin_toolbar_links_access_filter_help($route_name, RouteMatchInterface
  *
  * Hides links from admin menu, if user doesn't have access rights.
  */
+#[LegacyHook]
 function admin_toolbar_links_access_filter_preprocess_menu(&$variables) {
-  if (empty($variables['items'])) {
-    // Additional empty check to prevent exotic situations, where the preprocess
-    // function is entered even without items.
-    // @see https://www.drupal.org/node/2833885
-    return;
-  }
-  // Ensure that menu_name exists.
-  if (!isset($variables['menu_name'])) {
-    // In rare cases (for unknown reasons) menu_name may not be set.
-    // As fallback, we can fetch it from the first menu item.
-    $first_link = reset($variables['items']);
-    /** @var Drupal\Core\Menu\MenuLinkDefault $original_link */
-    // Fetch the menu_name from the original link.
-    $original_link = $first_link['original_link'];
-    $variables['menu_name'] = $original_link->getMenuName();
-  }
-  if ($variables['menu_name'] == 'admin') {
-    if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) {
-      admin_toolbar_links_access_filter_filter_non_accessible_links($variables['items']);
-    }
-  }
+  \Drupal::service(AdminToolbarLinksAccessFilterHooks::class)->preprocessMenu($variables);
 }
 
 /**
diff --git a/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.services.yml b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.services.yml
new file mode 100644
index 0000000..64255e7
--- /dev/null
+++ b/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\admin_toolbar_links_access_filter\Hook\AdminToolbarLinksAccessFilterHooks:
+    class: Drupal\admin_toolbar_links_access_filter\Hook\AdminToolbarLinksAccessFilterHooks
+    autowire: true
diff --git a/admin_toolbar_links_access_filter/src/Hook/AdminToolbarLinksAccessFilterHooks.php b/admin_toolbar_links_access_filter/src/Hook/AdminToolbarLinksAccessFilterHooks.php
new file mode 100644
index 0000000..3ce2754
--- /dev/null
+++ b/admin_toolbar_links_access_filter/src/Hook/AdminToolbarLinksAccessFilterHooks.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\admin_toolbar_links_access_filter\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for admin_toolbar_links_access_filter.
+ */
+class AdminToolbarLinksAccessFilterHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      // Main module help.
+      case 'help.page.admin_toolbar_links_access_filter':
+        $output = '';
+        $output .= '<h3>' . $this->t('About') . '</h3>';
+        $output .= '<p>' . $this->t('The Admin Toolbar Links Access Filter module provides a workaround for the common problem that users with <em>Use the administration pages and help</em> permission see menu links they done not have access permission for.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_preprocess_menu().
+   *
+   * Hides links from admin menu, if user doesn't have access rights.
+   */
+  #[Hook('preprocess_menu')]
+  public static function preprocessMenu(&$variables) {
+    if (empty($variables['items'])) {
+      // Additional empty check to prevent exotic situations, where the preprocess
+      // function is entered even without items.
+      // @see https://www.drupal.org/node/2833885
+      return;
+    }
+    // Ensure that menu_name exists.
+    if (!isset($variables['menu_name'])) {
+      // In rare cases (for unknown reasons) menu_name may not be set.
+      // As fallback, we can fetch it from the first menu item.
+      $first_link = reset($variables['items']);
+      /** @var Drupal\Core\Menu\MenuLinkDefault $original_link */
+      // Fetch the menu_name from the original link.
+      $original_link = $first_link['original_link'];
+      $variables['menu_name'] = $original_link->getMenuName();
+    }
+    if ($variables['menu_name'] == 'admin') {
+      if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) {
+        admin_toolbar_links_access_filter_filter_non_accessible_links($variables['items']);
+      }
+    }
+  }
+
+}
diff --git a/admin_toolbar_search/admin_toolbar_search.install b/admin_toolbar_search/admin_toolbar_search.install
index 5826632..f58d798 100644
--- a/admin_toolbar_search/admin_toolbar_search.install
+++ b/admin_toolbar_search/admin_toolbar_search.install
@@ -1,5 +1,11 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Component\Utility\DeprecationHelper;
+
 /**
  * @file
  * Install, update and uninstall functions for the Admin Toolbar Search module.
@@ -18,12 +24,16 @@ function admin_toolbar_search_update_8001() {
   $display_menu_item = $admin_toolbar_search_config->get('display_menu_item');
 
   // Update the configuration settings.
-  $admin_toolbar_search_config
+  DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $admin_toolbar_search_config
+    // Convert the existing field value from an integer to a boolean.
+    ->set('display_menu_item', (bool) $display_menu_item)
+    // Enable the keyboard shortcut by default.
+    ->set('enable_keyboard_shortcut', TRUE)->save(), fn() => $admin_toolbar_search_config
     // Convert the existing field value from an integer to a boolean.
     ->set('display_menu_item', (bool) $display_menu_item)
     // Enable the keyboard shortcut by default.
     ->set('enable_keyboard_shortcut', TRUE)
-    ->save(TRUE);
+    ->save(TRUE));
 }
 
 /**
diff --git a/admin_toolbar_search/admin_toolbar_search.module b/admin_toolbar_search/admin_toolbar_search.module
index 3ed6cab..01a8cf8 100644
--- a/admin_toolbar_search/admin_toolbar_search.module
+++ b/admin_toolbar_search/admin_toolbar_search.module
@@ -7,24 +7,15 @@
 
 declare(strict_types=1);
 
-use Drupal\admin_toolbar_search\Constants\AdminToolbarSearchConstants;
-use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Url;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\admin_toolbar_search\Hook\AdminToolbarSearchHooks;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function admin_toolbar_search_help($route_name) {
-  switch ($route_name) {
-    // Main user documentation page for the Admin Toolbar Search module.
-    case 'help.page.admin_toolbar_search':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('Type text to quickly search for menu links in the Admin Toolbar!<br>') . '</p>';
-      $output .= '<p>' . t('The Admin Toolbar Search module adds an easy-to-use JS autocomplete filter of the links in the Administration menu.<br>It is very convenient for finding quickly an administration configuration page without knowing where its menu link could be in the Administration dropdown menu or the organization of the site.') . '</p>';
-
-      return $output;
-  }
+  return \Drupal::service(AdminToolbarSearchHooks::class)->help($route_name);
 }
 
 /**
@@ -47,144 +38,7 @@ function admin_toolbar_search_help($route_name) {
  * @see admin_toolbar_search/css/admin_toolbar_search.css
  * @see admin_toolbar_search/js/admin_toolbar_search.js
  */
+#[LegacyHook]
 function admin_toolbar_search_toolbar() {
-  // Load the admin toolbar search only if the user has the required permission.
-  if (!\Drupal::currentUser()->hasPermission('use admin toolbar search')) {
-    return [];
-  }
-  // Check if the Admin Toolbar Tools module is enabled to load extra links.
-  $admin_toolbar_tools_enabled = \Drupal::service('module_handler')
-    ->moduleExists('admin_toolbar_tools');
-
-  // Load the Admin Toolbar Search settings from the configuration.
-  $admin_toolbar_search_settings = \Drupal::config('admin_toolbar_search.settings');
-  // Get the 'display_menu_item' setting to determine if the search field is
-  // displayed directly in the toolbar or in a tray under a menu item tab.
-  $display_menu_item = $admin_toolbar_search_settings->get('display_menu_item');
-  // Admin Toolbar Search field default label, title and placeholder text.
-  $search_field_title = t('Search');
-  $search_field_placeholder = t('Search for menu links');
-  $search_field_title_attribute = t('Type text to search for menu links in the admin toolbar.');
-
-  // Ensure the toolbar items are rebuilt when the user permissions or module's
-  // settings change and keep the render arrays cached.
-  $toolbar_search_item_cache = [
-    'contexts' => [
-      'user.permissions',
-    ],
-    'tags' => [
-      'config:admin_toolbar_search.settings',
-    ],
-  ];
-  // Render array of properties for the admin toolbar search JS autocomplete
-  // input text field.
-  $administration_search_field = [
-    'search' => [
-      // Define a form element of type 'search' to get HTML5 features.
-      '#type' => 'search',
-      // Set field HTML attributes: ID, label, title, placeholder text and size.
-      '#id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_input'],
-      '#title' => $search_field_title,
-      '#placeholder' => $search_field_placeholder,
-      '#attributes' => [
-        'title' => $search_field_title_attribute,
-      ],
-      // Default size of the search input field when displayed in the tray.
-      // The size is reduced when displayed directly in the toolbar.
-      '#size' => 60,
-    ],
-  ];
-
-  // Add the admin toolbar search as a toolbar item render array.
-  $items['administration_search'] = [
-    '#type' => 'toolbar_item',
-    'tab' => [
-      // Render array of properties for the admin search tab menu link, when it
-      // is *not* displayed directly in the toolbar or as a fallback for mobile.
-      '#type' => 'link',
-      '#title' => $search_field_title,
-      // Since the search field is handled with JS, there is no link url for the
-      // tab, so a simple 'span' element could be used instead.
-      '#url' => Url::fromRoute('<nolink>'),
-      '#attributes' => [
-        'class' => [
-          // Ensures compatibility with Drupal core toolbar styles for the
-          // search tab magnifying glass icon.
-          'toolbar-icon',
-        ],
-      ],
-    ],
-    // Move the search tab to the end of the toolbar items, by default.
-    '#weight' => 110,
-    // Set the ID of the HTML element wrapping the toolbar item.
-    '#wrapper_attributes' => [
-      'id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_tab'],
-    ],
-    // Load the required JS library and settings by default.
-    '#attached' => [
-      'library' => [
-        'admin_toolbar_search/admin_toolbar_search',
-      ],
-      // Add a setting to determine if extra links should be loaded via AJAX.
-      'drupalSettings' => [
-        'adminToolbarSearch' => [
-          'loadExtraLinks' => $admin_toolbar_tools_enabled,
-        ],
-      ],
-    ],
-    // Set the cache metadata for the administration search toolbar item.
-    '#cache' => $toolbar_search_item_cache,
-  ];
-
-  // Add the keyboard shortcut library if enabled ('enable_keyboard_shortcut').
-  if ($admin_toolbar_search_settings->get('enable_keyboard_shortcut')) {
-    $items['administration_search']['#attached']['library'][] = 'admin_toolbar_search/admin_toolbar_search.keyboard_shortcut';
-
-    // Add the keyboard shortcut label to the search field placeholder and
-    // title attributes.
-    $search_keyboard_shortcut_label = t('Alt + a');
-    $administration_search_field['search']['#placeholder'] .= ' (' . $search_keyboard_shortcut_label . ')';
-    $administration_search_field['search']['#attributes']['title'] = t('Keyboard shortcut: @shortcut_label', [
-      '@shortcut_label' => $search_keyboard_shortcut_label,
-    ]);
-  }
-
-  // The search field is always displayed in a specific tray under the 'Search'
-  // tab menu item. This tab is hidden or shown with CSS styles depending on the
-  // toolbar width breakpoint and the 'display_menu_item' setting.
-  $items['administration_search']['tray'] = $administration_search_field;
-
-  // Add the autocomplete search field directly in the toolbar by default, as
-  // a toolbar item ('display_menu_item:false').
-  if (!$display_menu_item) {
-    // The search field is displayed directly in the Toolbar without a tray.
-    $items['administration_search_field'] = [
-      '#type' => 'toolbar_item',
-      // Display the search field directly in the toolbar tab: Modify the search
-      // field properties for the toolbar item by merging the new options with
-      // the existing ones.
-      'tab' => NestedArray::mergeDeep($administration_search_field, [
-        'search' => [
-          // Reduce the size and hide the label of the search input field.
-          '#size' => 30,
-          '#title_display' => 'invisible',
-          // Set a different HTML ID for the search input field when displayed
-          // directly in the toolbar.
-          '#id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_field_input'],
-        ],
-      ]),
-      // The search field toolbar item should be right before the main search
-      // tab so it stays at the same position when the tab is hidden or shown.
-      '#weight' => $items['administration_search']['#weight'] - 1,
-      // Set the ID of the HTML element wrapping the toolbar item.
-      '#wrapper_attributes' => [
-        'id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_field_tab'],
-      ],
-      // Set the cache metadata for the admin search field toolbar item.
-      '#cache' => $toolbar_search_item_cache,
-    ];
-  }
-
-  return $items;
-
+  return \Drupal::service(AdminToolbarSearchHooks::class)->toolbar();
 }
diff --git a/admin_toolbar_search/admin_toolbar_search.services.yml b/admin_toolbar_search/admin_toolbar_search.services.yml
index b9a26a2..b2ac5bc 100644
--- a/admin_toolbar_search/admin_toolbar_search.services.yml
+++ b/admin_toolbar_search/admin_toolbar_search.services.yml
@@ -12,3 +12,7 @@ services:
       - '@cache_contexts_manager'
       - '@cache.toolbar'
       - '@config.factory'
+
+  Drupal\admin_toolbar_search\Hook\AdminToolbarSearchHooks:
+    class: Drupal\admin_toolbar_search\Hook\AdminToolbarSearchHooks
+    autowire: true
diff --git a/admin_toolbar_search/src/Hook/AdminToolbarSearchHooks.php b/admin_toolbar_search/src/Hook/AdminToolbarSearchHooks.php
new file mode 100644
index 0000000..5910db9
--- /dev/null
+++ b/admin_toolbar_search/src/Hook/AdminToolbarSearchHooks.php
@@ -0,0 +1,186 @@
+<?php
+
+namespace Drupal\admin_toolbar_search\Hook;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Url;
+use Drupal\admin_toolbar_search\Constants\AdminToolbarSearchConstants;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for admin_toolbar_search.
+ */
+class AdminToolbarSearchHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name) {
+    switch ($route_name) {
+      // Main user documentation page for the Admin Toolbar Search module.
+      case 'help.page.admin_toolbar_search':
+        $output = '';
+        $output .= '<h3>' . $this->t('About') . '</h3>';
+        $output .= '<p>' . $this->t('Type text to quickly search for menu links in the Admin Toolbar!<br>') . '</p>';
+        $output .= '<p>' . $this->t('The Admin Toolbar Search module adds an easy-to-use JS autocomplete filter of the links in the Administration menu.<br>It is very convenient for finding quickly an administration configuration page without knowing where its menu link could be in the Administration dropdown menu or the organization of the site.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_toolbar().
+   *
+   * Inject the admin toolbar search JS autocomplete text field in the Toolbar
+   * directly as a toolbar item or as a menu item tab with a tray
+   * ('display_menu_item'). Add the necessary CSS classes, HTML IDs and load
+   * required JS libraries and settings.
+   *
+   * The autocomplete search field is always loaded with a menu item tab and tray,
+   * but if the 'display_menu_item' setting is disabled, the search field is also
+   * added directly in the toolbar as a separate toolbar item.
+   * The default search tab is then hidden or displayed with CSS styles when the
+   * toolbar width is below '769px', to support mobile devices.
+   *
+   * In other words, support for smaller devices is not provided by the module,
+   * but by Drupal core.
+   *
+   * @see admin_toolbar_search/css/admin_toolbar_search.css
+   * @see admin_toolbar_search/js/admin_toolbar_search.js
+   */
+  #[Hook('toolbar')]
+  public function toolbar() {
+    // Load the admin toolbar search only if the user has the required permission.
+    if (!\Drupal::currentUser()->hasPermission('use admin toolbar search')) {
+      return [];
+    }
+    // Check if the Admin Toolbar Tools module is enabled to load extra links.
+    $admin_toolbar_tools_enabled = \Drupal::service('module_handler')->moduleExists('admin_toolbar_tools');
+    // Load the Admin Toolbar Search settings from the configuration.
+    $admin_toolbar_search_settings = \Drupal::config('admin_toolbar_search.settings');
+    // Get the 'display_menu_item' setting to determine if the search field is
+    // displayed directly in the toolbar or in a tray under a menu item tab.
+    $display_menu_item = $admin_toolbar_search_settings->get('display_menu_item');
+    // Admin Toolbar Search field default label, title and placeholder text.
+    $search_field_title = $this->t('Search');
+    $search_field_placeholder = $this->t('Search for menu links');
+    $search_field_title_attribute = $this->t('Type text to search for menu links in the admin toolbar.');
+    // Ensure the toolbar items are rebuilt when the user permissions or module's
+    // settings change and keep the render arrays cached.
+    $toolbar_search_item_cache = [
+      'contexts' => [
+        'user.permissions',
+      ],
+      'tags' => [
+        'config:admin_toolbar_search.settings',
+      ],
+    ];
+    // Render array of properties for the admin toolbar search JS autocomplete
+    // input text field.
+    $administration_search_field = [
+      'search' => [
+              // Define a form element of type 'search' to get HTML5 features.
+        '#type' => 'search',
+              // Set field HTML attributes: ID, label, title, placeholder text and size.
+        '#id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_input'],
+        '#title' => $search_field_title,
+        '#placeholder' => $search_field_placeholder,
+        '#attributes' => [
+          'title' => $search_field_title_attribute,
+        ],
+              // Default size of the search input field when displayed in the tray.
+              // The size is reduced when displayed directly in the toolbar.
+        '#size' => 60,
+      ],
+    ];
+    // Add the admin toolbar search as a toolbar item render array.
+    $items['administration_search'] = [
+      '#type' => 'toolbar_item',
+      'tab' => [
+              // Render array of properties for the admin search tab menu link, when it
+              // is *not* displayed directly in the toolbar or as a fallback for mobile.
+        '#type' => 'link',
+        '#title' => $search_field_title,
+              // Since the search field is handled with JS, there is no link url for the
+              // tab, so a simple 'span' element could be used instead.
+        '#url' => Url::fromRoute('<nolink>'),
+        '#attributes' => [
+          'class' => [
+                      // Ensures compatibility with Drupal core toolbar styles for the
+                      // search tab magnifying glass icon.
+            'toolbar-icon',
+          ],
+        ],
+      ],
+          // Move the search tab to the end of the toolbar items, by default.
+      '#weight' => 110,
+          // Set the ID of the HTML element wrapping the toolbar item.
+      '#wrapper_attributes' => [
+        'id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_tab'],
+      ],
+          // Load the required JS library and settings by default.
+      '#attached' => [
+        'library' => [
+          'admin_toolbar_search/admin_toolbar_search',
+        ],
+              // Add a setting to determine if extra links should be loaded via AJAX.
+        'drupalSettings' => [
+          'adminToolbarSearch' => [
+            'loadExtraLinks' => $admin_toolbar_tools_enabled,
+          ],
+        ],
+      ],
+          // Set the cache metadata for the administration search toolbar item.
+      '#cache' => $toolbar_search_item_cache,
+    ];
+    // Add the keyboard shortcut library if enabled ('enable_keyboard_shortcut').
+    if ($admin_toolbar_search_settings->get('enable_keyboard_shortcut')) {
+      $items['administration_search']['#attached']['library'][] = 'admin_toolbar_search/admin_toolbar_search.keyboard_shortcut';
+      // Add the keyboard shortcut label to the search field placeholder and
+      // title attributes.
+      $search_keyboard_shortcut_label = $this->t('Alt + a');
+      $administration_search_field['search']['#placeholder'] .= ' (' . $search_keyboard_shortcut_label . ')';
+      $administration_search_field['search']['#attributes']['title'] = $this->t('Keyboard shortcut: @shortcut_label', [
+        '@shortcut_label' => $search_keyboard_shortcut_label,
+      ]);
+    }
+    // The search field is always displayed in a specific tray under the 'Search'
+    // tab menu item. This tab is hidden or shown with CSS styles depending on the
+    // toolbar width breakpoint and the 'display_menu_item' setting.
+    $items['administration_search']['tray'] = $administration_search_field;
+    // Add the autocomplete search field directly in the toolbar by default, as
+    // a toolbar item ('display_menu_item:false').
+    if (!$display_menu_item) {
+      // The search field is displayed directly in the Toolbar without a tray.
+      $items['administration_search_field'] = [
+        '#type' => 'toolbar_item',
+            // Display the search field directly in the toolbar tab: Modify the search
+            // field properties for the toolbar item by merging the new options with
+            // the existing ones.
+        'tab' => NestedArray::mergeDeep($administration_search_field, [
+          'search' => [
+                    // Reduce the size and hide the label of the search input field.
+            '#size' => 30,
+            '#title_display' => 'invisible',
+                    // Set a different HTML ID for the search input field when displayed
+                    // directly in the toolbar.
+            '#id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_field_input'],
+          ],
+        ]),
+            // The search field toolbar item should be right before the main search
+            // tab so it stays at the same position when the tab is hidden or shown.
+        '#weight' => $items['administration_search']['#weight'] - 1,
+            // Set the ID of the HTML element wrapping the toolbar item.
+        '#wrapper_attributes' => [
+          'id' => AdminToolbarSearchConstants::ADMIN_TOOLBAR_SEARCH_HTML_IDS['search_field_tab'],
+        ],
+            // Set the cache metadata for the admin search field toolbar item.
+        '#cache' => $toolbar_search_item_cache,
+      ];
+    }
+    return $items;
+  }
+
+}
diff --git a/admin_toolbar_tools/admin_toolbar_tools.module b/admin_toolbar_tools/admin_toolbar_tools.module
index 414bb54..dca8b4c 100644
--- a/admin_toolbar_tools/admin_toolbar_tools.module
+++ b/admin_toolbar_tools/admin_toolbar_tools.module
@@ -7,96 +7,57 @@
 
 declare(strict_types=1);
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\admin_toolbar_tools\Hook\AdminToolbarToolsHooks;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\Url;
 
 /**
  * Implements hook_toolbar().
  */
+#[LegacyHook]
 function admin_toolbar_tools_toolbar() {
-  $items = [];
-  $items['admin_toolbar_tools'] = [
-    '#type' => 'toolbar_item',
-    'tab' => [
-      '#type' => 'link',
-      '#attributes' => [
-        'class' => ['toolbar-icon', 'toolbar-icon-admin-toolbar-tools-help'],
-      ],
-    ],
-    '#attached' => ['library' => ['admin_toolbar_tools/toolbar.icon']],
-  ];
-
-  // Toolbar item for primary local tasks.
-  $items['admin_toolbar_local_tasks'] = \Drupal::service('admin_toolbar_tools.helper')->buildLocalTasksToolbar();
-
-  return $items;
+  return \Drupal::service(AdminToolbarToolsHooks::class)->toolbar();
 }
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function admin_toolbar_tools_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.admin_toolbar_tools':
-      $output = '';
-      $output .= '<p>';
-      $output .= t('The Admin Toolbar Extra Tools module comes packaged with the <a href=":admin-toolbar">Admin Toolbar</a> module and adds functionality to it. The additional functionality is accessed through extra links on the main administration Toolbar. Some links to Admin Toolbar Extra Tools administration pages are located at the bottom of this page.</a>', [':admin-toolbar' => Url::fromRoute('help.page', ['name' => 'admin_toolbar'])->toString()]);
-      $output .= '</p>';
-      $output .= '<h3>' . t('Uses') . '</h3>';
-      $output .= '<p>' . t('To use Admin Toolbar Extra Tools just install it like any other module. There is no other configuration required.') . '</p>';
-      return $output;
-  }
+  return \Drupal::service(AdminToolbarToolsHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_entity_insert().
  */
+#[LegacyHook]
 function admin_toolbar_tools_entity_insert(EntityInterface $entity) {
-  // Skip rebuild during config sync because rebuild should
-  // always be a post-sync step.
-  if (!\Drupal::isConfigSyncing()) {
-    $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
-    if (in_array($entity->getEntityTypeId(), $entities)) {
-      \Drupal::service('plugin.manager.menu.link')->rebuild();
-    }
-  }
+  \Drupal::service(AdminToolbarToolsHooks::class)->entityInsert($entity);
 }
 
 /**
  * Implements hook_entity_update().
  */
+#[LegacyHook]
 function admin_toolbar_tools_entity_update(EntityInterface $entity) {
-  // Skip rebuild during config sync because rebuild should
-  // always be a post-sync step.
-  if (!\Drupal::isConfigSyncing()) {
-    $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
-    if (in_array($entity->getEntityTypeId(), $entities)) {
-      \Drupal::service('plugin.manager.menu.link')->rebuild();
-    }
-  }
+  \Drupal::service(AdminToolbarToolsHooks::class)->entityUpdate($entity);
 }
 
 /**
  * Implements hook_entity_delete().
  */
+#[LegacyHook]
 function admin_toolbar_tools_entity_delete(EntityInterface $entity) {
-  // Skip rebuild during config sync because rebuild should
-  // always be a post-sync step.
-  if (!\Drupal::isConfigSyncing()) {
-    $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
-    if (in_array($entity->getEntityTypeId(), $entities)) {
-      \Drupal::service('plugin.manager.menu.link')->rebuild();
-    }
-  }
+  \Drupal::service(AdminToolbarToolsHooks::class)->entityDelete($entity);
 }
 
 /**
  * Implements hook_form_FORM_ID_alter().
  */
+#[LegacyHook]
 function admin_toolbar_tools_form_project_browser_settings_alter(&$form) {
-  // Project browser settings form: Add a submit handler to rebuild menu items.
-  $form['#submit'][] = 'admin_toolbar_tools_project_browser_settings_submit';
+  \Drupal::service(AdminToolbarToolsHooks::class)->formProjectBrowserSettingsAlter($form);
 }
 
 /**
diff --git a/admin_toolbar_tools/admin_toolbar_tools.services.yml b/admin_toolbar_tools/admin_toolbar_tools.services.yml
index f910183..0f35fe6 100644
--- a/admin_toolbar_tools/admin_toolbar_tools.services.yml
+++ b/admin_toolbar_tools/admin_toolbar_tools.services.yml
@@ -6,3 +6,7 @@ services:
       - '@plugin.manager.menu.local_task'
       - '@current_route_match'
       - '@config.factory'
+
+  Drupal\admin_toolbar_tools\Hook\AdminToolbarToolsHooks:
+    class: Drupal\admin_toolbar_tools\Hook\AdminToolbarToolsHooks
+    autowire: true
diff --git a/admin_toolbar_tools/src/Controller/ToolbarController.php b/admin_toolbar_tools/src/Controller/ToolbarController.php
index f16cb1b..3ced572 100644
--- a/admin_toolbar_tools/src/Controller/ToolbarController.php
+++ b/admin_toolbar_tools/src/Controller/ToolbarController.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\admin_toolbar_tools\Controller;
 
+use Drupal\Component\Utility\DeprecationHelper;
 use Drupal\Core\Controller\ControllerBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -189,7 +190,7 @@ class ToolbarController extends ControllerBase {
     // @todo Remove deprecated code when support for core:10.2 is dropped.
     if (floatval(\Drupal::VERSION) < 10.2) {
       // @phpstan-ignore-next-line
-      _drupal_flush_css_js();
+      DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '10.2.0', fn() => \Drupal::service('asset.query_string')->reset(), fn() => _drupal_flush_css_js());
     }
     else {
       $this->assetQueryString->reset();
diff --git a/admin_toolbar_tools/src/Hook/AdminToolbarToolsHooks.php b/admin_toolbar_tools/src/Hook/AdminToolbarToolsHooks.php
new file mode 100644
index 0000000..ffc15ce
--- /dev/null
+++ b/admin_toolbar_tools/src/Hook/AdminToolbarToolsHooks.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Drupal\admin_toolbar_tools\Hook;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Url;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for admin_toolbar_tools.
+ */
+class AdminToolbarToolsHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_toolbar().
+   */
+  #[Hook('toolbar')]
+  public static function toolbar() {
+    $items = [];
+    $items['admin_toolbar_tools'] = [
+      '#type' => 'toolbar_item',
+      'tab' => [
+        '#type' => 'link',
+        '#attributes' => [
+          'class' => [
+            'toolbar-icon',
+            'toolbar-icon-admin-toolbar-tools-help',
+          ],
+        ],
+      ],
+      '#attached' => [
+        'library' => [
+          'admin_toolbar_tools/toolbar.icon',
+        ],
+      ],
+    ];
+    // Toolbar item for primary local tasks.
+    $items['admin_toolbar_local_tasks'] = \Drupal::service('admin_toolbar_tools.helper')->buildLocalTasksToolbar();
+    return $items;
+  }
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.admin_toolbar_tools':
+        $output = '';
+        $output .= '<p>';
+        $output .= $this->t('The Admin Toolbar Extra Tools module comes packaged with the <a href=":admin-toolbar">Admin Toolbar</a> module and adds functionality to it. The additional functionality is accessed through extra links on the main administration Toolbar. Some links to Admin Toolbar Extra Tools administration pages are located at the bottom of this page.</a>', [
+          ':admin-toolbar' => Url::fromRoute('help.page', [
+            'name' => 'admin_toolbar',
+          ])->toString(),
+        ]);
+        $output .= '</p>';
+        $output .= '<h3>' . $this->t('Uses') . '</h3>';
+        $output .= '<p>' . $this->t('To use Admin Toolbar Extra Tools just install it like any other module. There is no other configuration required.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_entity_insert().
+   */
+  #[Hook('entity_insert')]
+  public static function entityInsert(EntityInterface $entity) {
+    // Skip rebuild during config sync because rebuild should
+    // always be a post-sync step.
+    if (!\Drupal::isConfigSyncing()) {
+      $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
+      if (in_array($entity->getEntityTypeId(), $entities)) {
+        \Drupal::service('plugin.manager.menu.link')->rebuild();
+      }
+    }
+  }
+
+  /**
+   * Implements hook_entity_update().
+   */
+  #[Hook('entity_update')]
+  public static function entityUpdate(EntityInterface $entity) {
+    // Skip rebuild during config sync because rebuild should
+    // always be a post-sync step.
+    if (!\Drupal::isConfigSyncing()) {
+      $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
+      if (in_array($entity->getEntityTypeId(), $entities)) {
+        \Drupal::service('plugin.manager.menu.link')->rebuild();
+      }
+    }
+  }
+
+  /**
+   * Implements hook_entity_delete().
+   */
+  #[Hook('entity_delete')]
+  public static function entityDelete(EntityInterface $entity) {
+    // Skip rebuild during config sync because rebuild should
+    // always be a post-sync step.
+    if (!\Drupal::isConfigSyncing()) {
+      $entities = \Drupal::service('admin_toolbar_tools.helper')->getRebuildEntityTypes();
+      if (in_array($entity->getEntityTypeId(), $entities)) {
+        \Drupal::service('plugin.manager.menu.link')->rebuild();
+      }
+    }
+  }
+
+  /**
+   * Implements hook_form_FORM_ID_alter().
+   */
+  #[Hook('form_project_browser_settings_alter')]
+  public static function formProjectBrowserSettingsAlter(&$form) {
+    // Project browser settings form: Add a submit handler to rebuild menu items.
+    $form['#submit'][] = 'admin_toolbar_tools_project_browser_settings_submit';
+  }
+
+}
diff --git a/src/Hook/AdminToolbarHooks.php b/src/Hook/AdminToolbarHooks.php
new file mode 100644
index 0000000..2130f32
--- /dev/null
+++ b/src/Hook/AdminToolbarHooks.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Drupal\admin_toolbar\Hook;
+
+use Drupal\admin_toolbar\Render\Element\AdminToolbar;
+use Drupal\Core\Url;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for admin_toolbar.
+ */
+class AdminToolbarHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name) {
+    switch ($route_name) {
+      case 'help.page.admin_toolbar':
+        $variables = [
+          ':toolbar' => Url::fromRoute('help.page', [
+            'name' => 'toolbar',
+          ])->toString(),
+          ':automated_cron' => \Drupal::moduleHandler()->moduleExists('automated_cron') ? Url::fromRoute('help.page', [
+            'name' => 'automated_cron',
+          ])->toString() : '#',
+        ];
+        $output = '';
+        $output .= '<h3>' . $this->t('About') . '</h3>';
+        $output .= '<p>' . $this->t('The Admin Toolbar module enhances the <a href=":toolbar">Toolbar</a> module by providing fast access to all the administrative links at the top of your site. Admin Toolbar remains a very "lightweight" module by closely integrating with all Toolbar functionality. It can be used in conjunction with all the sub modules included on Admin Toolbar, for quick access to system commands such as Flush all caches, <a href=":automated_cron">Run cron</a>, Run Updates, etc.', $variables) . '</p>';
+        $output .= '<h3>' . $this->t('Uses') . '</h3>';
+        $output .= '<p>' . $this->t('The Admin Toolbar greatly improves the user experience for those who regularly interact with the site Toolbar by providing fast, full access to all links in the site Toolbar without having to click to get there.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_toolbar_alter().
+   */
+  #[Hook('toolbar_alter')]
+  public static function toolbarAlter(&$items) {
+    $items['administration']['tray']['toolbar_administration']['#pre_render'] = [
+          [
+            AdminToolbar::class,
+            'preRenderTray',
+          ],
+    ];
+    $admin_toolbar_config = \Drupal::config('admin_toolbar.settings');
+    $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree';
+    // Add sticky behavior libraries based on the configuration.
+    $sticky_behavior = $admin_toolbar_config->get('sticky_behavior') ?? 'enabled';
+    switch ($sticky_behavior) {
+      case 'disabled':
+        $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.disable_sticky';
+        break;
+
+      case 'hide_on_scroll_down':
+        $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.sticky_behavior';
+        break;
+
+      default:
+        break;
+    }
+    // Add the hoverIntent behavior library if enabled.
+    $hoverintent_behavior = $admin_toolbar_config->get('hoverintent_behavior');
+    if (!empty($hoverintent_behavior['enabled'])) {
+      // Use the hoverIntent plugin library.
+      $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree.hoverintent';
+      // Add the configured hoverIntent settings values to the JS of the toolbar.
+      $items['administration']['#attached']['drupalSettings']['hoverIntentTimeout'] = $hoverintent_behavior['timeout'];
+    }
+    else {
+      // Use default Admin Toolbar hover library.
+      $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.tree.hover';
+    }
+    // Add the toggle toolbar keyboard shortcut library if enabled.
+    if ($admin_toolbar_config->get('enable_toggle_shortcut')) {
+      $items['administration']['#attached']['library'][] = 'admin_toolbar/toolbar.toggle_shortcut';
+    }
+  }
+
+}
