diff --git a/prototype_select.module b/prototype_select.module
index b461df0..38dc7ec 100644
--- a/prototype_select.module
+++ b/prototype_select.module
@@ -1,5 +1,12 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\prototype_select\Hook\PrototypeSelectHooks;
+
 /**
  * @file
  * Primary module hooks for Prototype Select module.
@@ -23,43 +30,15 @@ function prototype_select_attach_library(array &$element) {
 /**
  * Implements hook_select_preprocess_select().
  */
+#[LegacyHook]
 function prototype_select_preprocess_select(array &$variables) {
-  $isEnabled = \Drupal::service('prototype_select.theme_options')->isThemeEnabled();
-
-  if (!$isEnabled) {
-    return;
-  }
-
-  $variables['attributes']['data-select-a11y'] = TRUE;
-  prototype_select_attach_library($variables);
+  \Drupal::service(PrototypeSelectHooks::class)->preprocessSelect($variables);
 }
 
 /**
  * Implements hook_page_attachments_alter().
  */
+#[LegacyHook]
 function prototype_select_page_attachments_alter(array &$attachments) {
-  // Add configuration settings if prototype_select is being added.
-  $config = \Drupal::config('prototype_select.settings');
-
-  $options = [
-    'searchEnabledThreshold' => (int) $config->get('search_enable_threshold'),
-    'maxResults' => (int) $config->get('max_shown_results'),
-    'searchContains' => (bool) $config->get('search_contains'),
-    'showSelected' => (bool) $config->get('show_selected'),
-    'text' => [
-      'help' => $config->get('text_help'),
-      'placeholder' => $config->get('text_placeholder'),
-      'noResult' => $config->get('text_no_result'),
-      'results' => $config->get('text_results'),
-      'deleteItem' => $config->get('text_delete_item'),
-      'delete' => $config->get('text_delete'),
-      'button' => $config->get('text_button'),
-    ],
-  ];
-
-  $attachments['#attached']['drupalSettings']['prototype_select'] = [
-    'selector' => $config->get('selector'),
-    'exclude_selector' => $config->get('exclude_selector'),
-    'options' => $options,
-  ];
+  \Drupal::service(PrototypeSelectHooks::class)->pageAttachmentsAlter($attachments);
 }
diff --git a/prototype_select.services.yml b/prototype_select.services.yml
index f1fd7fd..2f2837c 100644
--- a/prototype_select.services.yml
+++ b/prototype_select.services.yml
@@ -2,3 +2,7 @@ services:
   prototype_select.theme_options:
     class: Drupal\prototype_select\ThemeOptions
     arguments: ['@config.factory', '@theme.manager']
+
+  Drupal\prototype_select\Hook\PrototypeSelectHooks:
+    class: Drupal\prototype_select\Hook\PrototypeSelectHooks
+    autowire: true
diff --git a/src/Hook/PrototypeSelectHooks.php b/src/Hook/PrototypeSelectHooks.php
new file mode 100644
index 0000000..b30d73a
--- /dev/null
+++ b/src/Hook/PrototypeSelectHooks.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\prototype_select\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for prototype_select.
+ */
+class PrototypeSelectHooks {
+
+  /**
+   * Implements hook_select_preprocess_select().
+   */
+  #[Hook('select_preprocess_select', module: 'prototype')]
+  public function preprocessSelect(array &$variables) {
+    $isEnabled = \Drupal::service('prototype_select.theme_options')->isThemeEnabled();
+    if (!$isEnabled) {
+      return;
+    }
+    $variables['attributes']['data-select-a11y'] = TRUE;
+    prototype_select_attach_library($variables);
+  }
+
+  /**
+   * Implements hook_page_attachments_alter().
+   */
+  #[Hook('page_attachments_alter')]
+  public function pageAttachmentsAlter(array &$attachments) {
+    // Add configuration settings if prototype_select is being added.
+    $config = \Drupal::config('prototype_select.settings');
+    $options = [
+      'searchEnabledThreshold' => (int) $config->get('search_enable_threshold'),
+      'maxResults' => (int) $config->get('max_shown_results'),
+      'searchContains' => (bool) $config->get('search_contains'),
+      'showSelected' => (bool) $config->get('show_selected'),
+      'text' => [
+        'help' => $config->get('text_help'),
+        'placeholder' => $config->get('text_placeholder'),
+        'noResult' => $config->get('text_no_result'),
+        'results' => $config->get('text_results'),
+        'deleteItem' => $config->get('text_delete_item'),
+        'delete' => $config->get('text_delete'),
+        'button' => $config->get('text_button'),
+      ],
+    ];
+    $attachments['#attached']['drupalSettings']['prototype_select'] = [
+      'selector' => $config->get('selector'),
+      'exclude_selector' => $config->get('exclude_selector'),
+      'options' => $options,
+    ];
+  }
+
+}
