diff --git a/improved_multi_select.info.yml b/improved_multi_select.info.yml
index fcf4ee8..782942d 100755
--- a/improved_multi_select.info.yml
+++ b/improved_multi_select.info.yml
@@ -2,7 +2,7 @@ package: Form Elements
 name: 'Improved Multi Select'
 type: module
 description: 'The Improved Multi Select module improve UX by replacing default multi-select boxes with two panel list and search box.'
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 configure: ims.settings
 libraries:
   - improved_multi_select/ims
diff --git a/improved_multi_select.module b/improved_multi_select.module
index e26c918..1228518 100755
--- a/improved_multi_select.module
+++ b/improved_multi_select.module
@@ -4,58 +4,17 @@
  * @file
  * Replace the default multi-select boxes with two panels list and filter.
  */
-
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\improved_multi_select\Hook\ImprovedMultiSelectHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_page_attachments().
  */
-function improved_multi_select_page_attachments(&$attachments) {
-  $activated = FALSE;
-  $config = \Drupal::config('improved_multi_select.settings');
-  $context = [
-    'url'          => trim($config->get('url')),
-    'request_path' => \Drupal::request()->getRequestUri(),
-    'selectors'    => array_filter(explode("\n", str_replace("\r", "\n", trim($config->get('selectors'))))),
-  ];
-
-  // Activated on replace all option.
-  if ($replace_all = $config->get('isall')) {
-    $activated = TRUE;
-  }
-  // Activated based on the matching path or not empty selectors in the module
-  // settings.
-  elseif (($context['url'] && \Drupal::service('path.matcher')->matchPath($context['request_path'], $context['url'])) || $context['selectors']) {
-    $activated = TRUE;
-  }
-
-  // Allow other modules to activate/deactivate the module for specific pages.
-  \Drupal::moduleHandler()->alter('improved_multi_select_activated', $activated, $context);
-  if (!$activated) {
-    return;
-  }
-
-  $drupal_settings = [
-    'selectors'            => improved_multi_select_load_selectors($replace_all, $context['selectors']),
-    'filtertype'           => $config->get('filtertype'),
-    'placeholder_text'     => $config->get('placeholder_text'),
-    'orderable'            => $config->get('orderable'),
-    'js_regex'             => $config->get('js_regex'),
-    'groupresetfilter'     => $config->get('groupresetfilter'),
-    'remove_required_attr' => $config->get('remove_required_attr'),
-    'buttontext_add'       => $config->get('buttontext_add'),
-    'buttontext_addall'    => $config->get('buttontext_addall'),
-    'buttontext_del'       => $config->get('buttontext_del'),
-    'buttontext_delall'    => $config->get('buttontext_delall'),
-    'buttontext_moveup'    => $config->get('buttontext_moveup'),
-    'buttontext_movedown'  => $config->get('buttontext_movedown'),
-  ];
-
-  // Allow other modules to alter our data.
-  \Drupal::moduleHandler()->alter('improved_multi_select_attached', $drupal_settings, $context);
-
-  $attachments['#attached']['library'][] = 'improved_multi_select/ims';
-  $attachments['#attached']['drupalSettings']['improved_multi_select'] = $drupal_settings;
+#[LegacyHook]
+function improved_multi_select_page_attachments(&$attachments)
+{
+    \Drupal::service(ImprovedMultiSelectHooks::class)->pageAttachments($attachments);
 }
 
 /**
@@ -89,24 +48,8 @@ function improved_multi_select_load_selectors(bool $replace_all, array $selector
  *
  * @inheritdoc
  */
-function improved_multi_select_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.improved_multi_select':
-      $text = file_get_contents(dirname(__FILE__) . '/README.txt');
-      if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
-        return '<pre>' . $text . '</pre>';
-      }
-
-      // Use the Markdown filter to render the README.
-      $filter_manager = \Drupal::service('plugin.manager.filter');
-      $settings = \Drupal::configFactory()
-        ->get('markdown.settings')
-        ->getRawData();
-      $config = ['settings' => $settings];
-      $filter = $filter_manager->createInstance('markdown', $config);
-
-      return $filter->process($text, 'en');
-
-  }
-  return NULL;
+#[LegacyHook]
+function improved_multi_select_help($route_name, RouteMatchInterface $route_match)
+{
+    return \Drupal::service(ImprovedMultiSelectHooks::class)->help($route_name, $route_match);
 }
diff --git a/improved_multi_select.services.yml b/improved_multi_select.services.yml
new file mode 100644
index 0000000..cbb2f90
--- /dev/null
+++ b/improved_multi_select.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\improved_multi_select\Hook\ImprovedMultiSelectHooks:
+    class: Drupal\improved_multi_select\Hook\ImprovedMultiSelectHooks
+    autowire: true
diff --git a/modules/ims_options_widget/ims_options_widget.info.yml b/modules/ims_options_widget/ims_options_widget.info.yml
index 6169014..e539e82 100644
--- a/modules/ims_options_widget/ims_options_widget.info.yml
+++ b/modules/ims_options_widget/ims_options_widget.info.yml
@@ -2,7 +2,7 @@ package: Form Elements
 name: 'IMS Options Widget'
 type: module
 description: 'Provides a Select Lists widget which keeps previously selected values on top of the available options.'
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 dependencies:
   - drupal:options
   - improved_multi_select:improved_multi_select
diff --git a/modules/ims_options_widget/tests/src/Functional/ImsOptionsWidgetsTest.php b/modules/ims_options_widget/tests/src/Functional/ImsOptionsWidgetsTest.php
index caeedcc..f166346 100644
--- a/modules/ims_options_widget/tests/src/Functional/ImsOptionsWidgetsTest.php
+++ b/modules/ims_options_widget/tests/src/Functional/ImsOptionsWidgetsTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\ims_options_widget\Tests\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\field\Entity\FieldConfig;
@@ -15,6 +17,8 @@ use Drupal\Tests\field\Functional\FieldTestBase;
  *
  * @package Drupal\ims_options_widget\Testss
  */
+#[Group('Improved Multi Select')]
+#[RunTestsInSeparateProcesses]
 class ImsOptionsWidgetsTest extends FieldTestBase {
 
   use StringTranslationTrait;
diff --git a/src/Hook/ImprovedMultiSelectHooks.php b/src/Hook/ImprovedMultiSelectHooks.php
new file mode 100644
index 0000000..30dab25
--- /dev/null
+++ b/src/Hook/ImprovedMultiSelectHooks.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\improved_multi_select\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+/**
+ * Hook implementations for improved_multi_select.
+ */
+class ImprovedMultiSelectHooks
+{
+    /**
+     * Implements hook_page_attachments().
+     */
+    #[Hook('page_attachments')]
+    public static function pageAttachments(&$attachments)
+    {
+        $activated = FALSE;
+        $config = \Drupal::config('improved_multi_select.settings');
+        $context = [
+            'url' => trim($config->get('url')),
+            'request_path' => \Drupal::request()->getRequestUri(),
+            'selectors' => array_filter(explode("\n", str_replace("\r", "\n", trim($config->get('selectors'))))),
+        ];
+        // Activated on replace all option.
+        if ($replace_all = $config->get('isall')) {
+            $activated = TRUE;
+        } elseif ($context['url'] && \Drupal::service('path.matcher')->matchPath($context['request_path'], $context['url']) || $context['selectors']) {
+            $activated = TRUE;
+        }
+        // Allow other modules to activate/deactivate the module for specific pages.
+        \Drupal::moduleHandler()->alter('improved_multi_select_activated', $activated, $context);
+        if (!$activated) {
+            return;
+        }
+        $drupal_settings = [
+            'selectors' => improved_multi_select_load_selectors($replace_all, $context['selectors']),
+            'filtertype' => $config->get('filtertype'),
+            'placeholder_text' => $config->get('placeholder_text'),
+            'orderable' => $config->get('orderable'),
+            'js_regex' => $config->get('js_regex'),
+            'groupresetfilter' => $config->get('groupresetfilter'),
+            'remove_required_attr' => $config->get('remove_required_attr'),
+            'buttontext_add' => $config->get('buttontext_add'),
+            'buttontext_addall' => $config->get('buttontext_addall'),
+            'buttontext_del' => $config->get('buttontext_del'),
+            'buttontext_delall' => $config->get('buttontext_delall'),
+            'buttontext_moveup' => $config->get('buttontext_moveup'),
+            'buttontext_movedown' => $config->get('buttontext_movedown'),
+        ];
+        // Allow other modules to alter our data.
+        \Drupal::moduleHandler()->alter('improved_multi_select_attached', $drupal_settings, $context);
+        $attachments['#attached']['library'][] = 'improved_multi_select/ims';
+        $attachments['#attached']['drupalSettings']['improved_multi_select'] = $drupal_settings;
+    }
+    /**
+     * Implements hook_help().
+     *
+     * @inheritdoc
+     */
+    #[Hook('help')]
+    public static function help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_match)
+    {
+        switch ($route_name) {
+            case 'help.page.improved_multi_select':
+                $text = file_get_contents(dirname(__FILE__) . '/README.txt');
+                if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
+                    return '<pre>' . $text . '</pre>';
+                }
+                // Use the Markdown filter to render the README.
+                $filter_manager = \Drupal::service('plugin.manager.filter');
+                $settings = \Drupal::configFactory()->get('markdown.settings')->getRawData();
+                $config = [
+                    'settings' => $settings,
+                ];
+                $filter = $filter_manager->createInstance('markdown', $config);
+                return $filter->process($text, 'en');
+        }
+        return NULL;
+    }
+}
diff --git a/src/Tests/Functional/ImprovedMultiSelectTests.php b/src/Tests/Functional/ImprovedMultiSelectTests.php
index 4e98fae..6455d38 100644
--- a/src/Tests/Functional/ImprovedMultiSelectTests.php
+++ b/src/Tests/Functional/ImprovedMultiSelectTests.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\improved_multi_select\Tests\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -13,6 +15,8 @@ use Drupal\Tests\BrowserTestBase;
  *
  * @package Drupal\improved_multi_select\Tests
  */
+#[Group('Improved Multi Select')]
+#[RunTestsInSeparateProcesses]
 class ImprovedMultiSelectTests extends BrowserTestBase {
 
   /**
