diff --git a/ckeditor_infocard.info.yml b/ckeditor_infocard.info.yml
index 29b40f5..0cf4cf5 100644
--- a/ckeditor_infocard.info.yml
+++ b/ckeditor_infocard.info.yml
@@ -1,7 +1,7 @@
 name: CKEditor InfoCard
 type: module
 description: Adds CKEditor Infocard using span button.
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 package: CKEditor
 dependencies:
   - drupal:ckeditor5
diff --git a/ckeditor_infocard.module b/ckeditor_infocard.module
index bfef217..7beda88 100644
--- a/ckeditor_infocard.module
+++ b/ckeditor_infocard.module
@@ -5,38 +5,22 @@
  * Contains ckeditor_infocard.module.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\ckeditor_infocard\Hook\CkeditorInfocardHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\Url;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function ckeditor_infocard_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.ckeditor_infocard':
-      $output = '';
-      $output .= '<h3>' . t('CKEditor InfoCard') . '</h3>';
-      $output .= '<p>' . t('The module adds a CKEditor InfoCard button to the editor toolbar and a link to its context menu (only available if you select an existing span with class js-infoCard tag in the editor content).') . '</p>';
-      $output .= '<h3>' . t('Uses') . '</h3>';
-      $output .= '<dl>';
-      $output .= '<dt>' . t('Settings') . '</dt>';
-      $output .= '<dd>' . t('In the <a href=":text-formats">text formats</a> that use ckeditor, move the icon into the active toolbar.', [':text-formats' => Url::fromRoute('filter.admin_overview')->toString()]) . '</dd>';
-      $output .= '<dt>' . t('Usage') . '</dt>';
-      $output .= '<dd>' . t('Select the infocard you want to tag. Click the ckeditor infocard icon and fill in the fields in the opening dialog.') . '</dd>';
-      $output .= '<dd>' . t('To edit a tagged infocard place the cursor within the infocard text and click the ckeditor infocard icon. Or open the context menu by right-clicking on your mouse and select "Edit InfoCard".') . '</dd>';
-      $output .= '<dd>' . t('To remove an infocard title infocard, delete the explanation in the ckeditor infocard dialog. In order to untag an infocard, delete the infocard in the ckeditor infocard dialog.') . '</dd>';
-      $output .= '</dl>';
-      return $output;
-
-    default:
-      return '';
-  }
+  return \Drupal::service(CkeditorInfocardHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_page_attachments_alter().
  */
+#[LegacyHook]
 function ckeditor_infocard_page_attachments_alter(array &$page) {
-  // Attaches css assets globally.
-  $page['#attached']['library'][] = 'ckeditor_infocard/infocard.frontend';
+  \Drupal::service(CkeditorInfocardHooks::class)->pageAttachmentsAlter($page);
 }
diff --git a/ckeditor_infocard.services.yml b/ckeditor_infocard.services.yml
new file mode 100644
index 0000000..8dad39d
--- /dev/null
+++ b/ckeditor_infocard.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\ckeditor_infocard\Hook\CkeditorInfocardHooks:
+    class: Drupal\ckeditor_infocard\Hook\CkeditorInfocardHooks
+    autowire: true
diff --git a/composer.json b/composer.json
index 9334cdd..f8f5cd7 100644
--- a/composer.json
+++ b/composer.json
@@ -11,6 +11,6 @@
         "source": "http://cgit.drupalcode.org/ckeditor_infocard"
     },
     "require": {
-        "drupal/core": "^10 || ^11"
+        "drupal/core": "^10.1 || ^11 || ^12"
     }
 }
diff --git a/src/Hook/CkeditorInfocardHooks.php b/src/Hook/CkeditorInfocardHooks.php
new file mode 100644
index 0000000..3fe7057
--- /dev/null
+++ b/src/Hook/CkeditorInfocardHooks.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\ckeditor_infocard\Hook;
+
+use Drupal\Core\Url;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for ckeditor_infocard.
+ */
+class CkeditorInfocardHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.ckeditor_infocard':
+        $output = '';
+        $output .= '<h3>' . $this->t('CKEditor InfoCard') . '</h3>';
+        $output .= '<p>' . $this->t('The module adds a CKEditor InfoCard button to the editor toolbar and a link to its context menu (only available if you select an existing span with class js-infoCard tag in the editor content).') . '</p>';
+        $output .= '<h3>' . $this->t('Uses') . '</h3>';
+        $output .= '<dl>';
+        $output .= '<dt>' . $this->t('Settings') . '</dt>';
+        $output .= '<dd>' . $this->t('In the <a href=":text-formats">text formats</a> that use ckeditor, move the icon into the active toolbar.', [
+          ':text-formats' => Url::fromRoute('filter.admin_overview')->toString(),
+        ]) . '</dd>';
+        $output .= '<dt>' . $this->t('Usage') . '</dt>';
+        $output .= '<dd>' . $this->t('Select the infocard you want to tag. Click the ckeditor infocard icon and fill in the fields in the opening dialog.') . '</dd>';
+        $output .= '<dd>' . $this->t('To edit a tagged infocard place the cursor within the infocard text and click the ckeditor infocard icon. Or open the context menu by right-clicking on your mouse and select "Edit InfoCard".') . '</dd>';
+        $output .= '<dd>' . $this->t('To remove an infocard title infocard, delete the explanation in the ckeditor infocard dialog. In order to untag an infocard, delete the infocard in the ckeditor infocard dialog.') . '</dd>';
+        $output .= '</dl>';
+        return $output;
+
+      default:
+        return '';
+    }
+  }
+
+  /**
+   * Implements hook_page_attachments_alter().
+   */
+  #[Hook('page_attachments_alter')]
+  public function pageAttachmentsAlter(array &$page) {
+    // Attaches css assets globally.
+    $page['#attached']['library'][] = 'ckeditor_infocard/infocard.frontend';
+  }
+
+}
diff --git a/tests/src/FunctionalJavascript/CKEditorInfoCardTest.php b/tests/src/FunctionalJavascript/CKEditorInfoCardTest.php
index 408affa..773fd6f 100644
--- a/tests/src/FunctionalJavascript/CKEditorInfoCardTest.php
+++ b/tests/src/FunctionalJavascript/CKEditorInfoCardTest.php
@@ -4,6 +4,8 @@ declare(strict_types=1);
 
 namespace Drupal\Tests\ckeditor_infocard\FunctionalJavascript;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\editor\Entity\Editor;
 use Drupal\filter\Entity\FilterFormat;
 use Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5TestBase;
@@ -17,6 +19,8 @@ use Drupal\user\RoleInterface;
  *
  * @group ckeditor_infocard
  */
+#[Group('ckeditor_infocard')]
+#[RunTestsInSeparateProcesses]
 class CKEditorInfoCardTest extends CKEditor5TestBase {
   use CKEditor5TestTrait;
 
