diff --git a/node_id_class.info.yml b/node_id_class.info.yml
index f9d43e5..f60d131 100644
--- a/node_id_class.info.yml
+++ b/node_id_class.info.yml
@@ -1,6 +1,6 @@
 name: Node ID Class
 type: module
 description: Provides an easy way to assign dynamic CSS IDs and classes to node wrappers and the body element, using tokens like {node_id}, {bundle}, {node_title} and {node_author_uid} for flexible theming and layout control.
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 dependencies:
   - drupal:node
diff --git a/node_id_class.module b/node_id_class.module
index d1af158..23e6fa4 100644
--- a/node_id_class.module
+++ b/node_id_class.module
@@ -5,6 +5,8 @@
  * Provides functionalities for assigning dynamic CSS IDs and classes to nodes.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\node_id_class\Hook\NodeIdClassHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\node\NodeTypeInterface;
@@ -15,58 +17,9 @@ use Drupal\Component\Utility\Html;
  *
  * Adds a fieldset to the node type edit form for custom IDs and classes.
  */
+#[LegacyHook]
 function node_id_class_form_node_type_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
-  /** @var \Drupal\node\NodeTypeInterface $type */
-  $type = $form_state->getFormObject()->getEntity();
-
-  // Retrieve saved third-party settings.
-  $body_id = $type->getThirdPartySetting('node_id_class', 'body_id', '');
-  $body_class = $type->getThirdPartySetting('node_id_class', 'body_class', '');
-  $node_class = $type->getThirdPartySetting('node_id_class', 'node_class', '');
-
-  // Add fieldset.
-  $form['node_id_class_fieldset'] = [
-    '#type' => 'details',
-    '#title' => t('Node ID Class'),
-    '#group' => 'additional_settings',
-    '#weight' => 1,
-    '#attached' => [
-      'library' => ['node_id_class/node_id_class.classes'],
-    ],
-  ];
-
-  // CSS Body ID field with validation.
-  $form['node_id_class_fieldset']['body_id'] = [
-    '#type' => 'textfield',
-    '#title' => t('CSS Body ID'),
-    '#description' => t('Applied to the &lt;body&gt; element on full node pages. Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: body-id-{node_id}-{bundle}-{node_title}, node--{node_author_uid}'),
-    '#default_value' => $body_id,
-    '#element_validate' => ['node_id_class_validate_css_classes', 'node_id_class_validate_css_id'],
-    '#maxlength' => 128,
-  ];
-
-  // CSS Body Classes field with validation.
-  $form['node_id_class_fieldset']['body_class'] = [
-    '#type' => 'textfield',
-    '#title' => t('CSS Body Class(es)'),
-    '#description' => t('Applied to the &lt;body&gt; element on full node pages. Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: body-class-{node_id}-{bundle}, node--{node_author_uid}'),
-    '#default_value' => $body_class,
-    '#element_validate' => ['node_id_class_validate_css_classes'],
-    '#maxlength' => 255,
-  ];
-
-  // CSS Node Classes field with validation.
-  $form['node_id_class_fieldset']['node_class'] = [
-    '#type' => 'textfield',
-    '#title' => t('CSS Node Class(es)'),
-    '#description' => t('Applied to the node wrapper in all view modes and listings (e.g., Views). Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: node-class-{node_id}-{bundle}-{node_title}, node--{node_author_uid}'),
-    '#default_value' => $node_class,
-    '#element_validate' => ['node_id_class_validate_css_classes'],
-    '#maxlength' => 255,
-  ];
-
-  // Save settings when the form is submitted.
-  $form['#entity_builders'][] = 'node_id_class_node_type_entity_builder';
+  \Drupal::service(NodeIdClassHooks::class)->formNodeTypeEditFormAlter($form, $form_state, $form_id);
 }
 
 /**
@@ -131,41 +84,9 @@ function node_id_class_validate_css_id($element, FormStateInterface $form_state,
  *
  * Adds custom body ID and class for nodes.
  */
+#[LegacyHook]
 function node_id_class_preprocess_html(array &$variables) {
-  $node = \Drupal::routeMatch()->getParameter('node');
-  if ($node) {
-    $node_type = $node->bundle();
-    $type = \Drupal::entityTypeManager()->getStorage('node_type')->load($node_type);
-
-    $body_id = $type->getThirdPartySetting('node_id_class', 'body_id', '');
-    $body_class = $type->getThirdPartySetting('node_id_class', 'body_class', '');
-
-    if ($body_id || $body_class) {
-      $tokens = [
-        '{node_id}' => $node->id(),
-        '{node_title}' => node_id_class_generate_slug($node->getTitle()),
-        '{node_author_uid}' => $node->getOwnerId(),
-        '{bundle}' => $node_type,
-      ];
-    }
-
-    if ($body_id) {
-      $variables['attributes']['id'] = Html::escape(strtr($body_id, $tokens));
-    }
-
-    if ($body_class) {
-      $raw = strtr($body_class, $tokens);
-      $classes = preg_split('/\s+/', $raw);
-
-      if ($classes) {
-        foreach ($classes as $class) {
-          if ($class !== '') {
-            $variables['attributes']['class'][] = Html::escape($class);
-          }
-        }
-      }
-    }
-  }
+  \Drupal::service(NodeIdClassHooks::class)->preprocessHtml($variables);
 }
 
 /**
@@ -173,32 +94,9 @@ function node_id_class_preprocess_html(array &$variables) {
  *
  * Adds custom node class.
  */
+#[LegacyHook]
 function node_id_class_preprocess_node(array &$variables) {
-  if (isset($variables['node'])) {
-    $node = $variables['node'];
-    $type = \Drupal::entityTypeManager()->getStorage('node_type')->load($node->bundle());
-    $node_class = $type->getThirdPartySetting('node_id_class', 'node_class', '');
-
-    if ($node_class) {
-      $tokens = [
-        '{node_id}' => $node->id(),
-        '{node_title}' => node_id_class_generate_slug($node->getTitle()),
-        '{node_author_uid}' => $node->getOwnerId(),
-        '{bundle}' => $node->bundle(),
-      ];
-
-      $raw = strtr($node_class, $tokens);
-      $classes = preg_split('/\s+/', $raw);
-
-      if ($classes) {
-        foreach ($classes as $class) {
-          if ($class !== '') {
-            $variables['attributes']['class'][] = Html::escape($class);
-          }
-        }
-      }
-    }
-  }
+  \Drupal::service(NodeIdClassHooks::class)->preprocessNode($variables);
 }
 
 /**
@@ -212,17 +110,7 @@ function node_id_class_generate_slug(string $string): string {
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function node_id_class_help($route_name, RouteMatchInterface $route_match) {
-  if ($route_name === 'help.page.node_id_class') {
-    return '<h2>' . t('Node ID Class') . '</h2>'
-      . '<p>' . t('The Node ID Class module enables site builders to add dynamic CSS IDs and classes to the <code>&lt;body&gt;</code> element and node wrappers. You can use tokens such as {node_id}, {node_title}, {bundle}, and {node_author_uid} to generate dynamic, theme-friendly class names and IDs.') . '</p>'
-      . '<h3>' . t('Key Features') . '</h3>'
-      . '<ul>'
-      . '<li>' . t('Add custom CSS Body ID to full node pages.') . '</li>'
-      . '<li>' . t('Add multiple CSS Body Classes.') . '</li>'
-      . '<li>' . t('Add multiple CSS Node Classes to node wrappers and Views listings.') . '</li>'
-      . '<li>' . t('Supports dynamic tokens for flexible theming: {node_id}, {node_title}, {bundle}, {node_author_uid}.') . '</li>'
-      . '<li>' . t('Inputs are validated and sanitized to prevent XSS or invalid markup.') . '</li>'
-      . '</ul>';
-  }
+  return \Drupal::service(NodeIdClassHooks::class)->help($route_name, $route_match);
 }
diff --git a/node_id_class.services.yml b/node_id_class.services.yml
new file mode 100644
index 0000000..9cd0441
--- /dev/null
+++ b/node_id_class.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\node_id_class\Hook\NodeIdClassHooks:
+    class: Drupal\node_id_class\Hook\NodeIdClassHooks
+    autowire: true
diff --git a/src/Hook/NodeIdClassHooks.php b/src/Hook/NodeIdClassHooks.php
new file mode 100644
index 0000000..8e4c0a6
--- /dev/null
+++ b/src/Hook/NodeIdClassHooks.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Drupal\node_id_class\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for node_id_class.
+ */
+class NodeIdClassHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_form_FORM_ID_alter().
+   *
+   * Adds a fieldset to the node type edit form for custom IDs and classes.
+   */
+  #[Hook('form_node_type_edit_form_alter')]
+  public function formNodeTypeEditFormAlter(&$form, FormStateInterface $form_state, $form_id) {
+    /** @var \Drupal\node\NodeTypeInterface $type */
+    $type = $form_state->getFormObject()->getEntity();
+    // Retrieve saved third-party settings.
+    $body_id = $type->getThirdPartySetting('node_id_class', 'body_id', '');
+    $body_class = $type->getThirdPartySetting('node_id_class', 'body_class', '');
+    $node_class = $type->getThirdPartySetting('node_id_class', 'node_class', '');
+    // Add fieldset.
+    $form['node_id_class_fieldset'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Node ID Class'),
+      '#group' => 'additional_settings',
+      '#weight' => 1,
+      '#attached' => [
+        'library' => [
+          'node_id_class/node_id_class.classes',
+        ],
+      ],
+    ];
+    // CSS Body ID field with validation.
+    $form['node_id_class_fieldset']['body_id'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('CSS Body ID'),
+      '#description' => $this->t('Applied to the &lt;body&gt; element on full node pages. Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: body-id-{node_id}-{bundle}-{node_title}, node--{node_author_uid}'),
+      '#default_value' => $body_id,
+      '#element_validate' => [
+        'node_id_class_validate_css_classes',
+        'node_id_class_validate_css_id',
+      ],
+      '#maxlength' => 128,
+    ];
+    // CSS Body Classes field with validation.
+    $form['node_id_class_fieldset']['body_class'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('CSS Body Class(es)'),
+      '#description' => $this->t('Applied to the &lt;body&gt; element on full node pages. Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: body-class-{node_id}-{bundle}, node--{node_author_uid}'),
+      '#default_value' => $body_class,
+      '#element_validate' => [
+        'node_id_class_validate_css_classes',
+      ],
+      '#maxlength' => 255,
+    ];
+    // CSS Node Classes field with validation.
+    $form['node_id_class_fieldset']['node_class'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('CSS Node Class(es)'),
+      '#description' => $this->t('Applied to the node wrapper in all view modes and listings (e.g., Views). Supports tokens: {node_id}, {bundle}, {node_title}, {node_author_uid}.<br/>Example: node-class-{node_id}-{bundle}-{node_title}, node--{node_author_uid}'),
+      '#default_value' => $node_class,
+      '#element_validate' => [
+        'node_id_class_validate_css_classes',
+      ],
+      '#maxlength' => 255,
+    ];
+    // Save settings when the form is submitted.
+    $form['#entity_builders'][] = 'node_id_class_node_type_entity_builder';
+  }
+
+  /**
+   * Implements hook_preprocess_html().
+   *
+   * Adds custom body ID and class for nodes.
+   */
+  #[Hook('preprocess_html')]
+  public function preprocessHtml(array &$variables) {
+    $node = \Drupal::routeMatch()->getParameter('node');
+    if ($node) {
+      $node_type = $node->bundle();
+      $type = \Drupal::entityTypeManager()->getStorage('node_type')->load($node_type);
+      $body_id = $type->getThirdPartySetting('node_id_class', 'body_id', '');
+      $body_class = $type->getThirdPartySetting('node_id_class', 'body_class', '');
+      if ($body_id || $body_class) {
+        $tokens = [
+          '{node_id}' => $node->id(),
+          '{node_title}' => node_id_class_generate_slug($node->getTitle()),
+          '{node_author_uid}' => $node->getOwnerId(),
+          '{bundle}' => $node_type,
+        ];
+      }
+      if ($body_id) {
+        $variables['attributes']['id'] = Html::escape(strtr($body_id, $tokens));
+      }
+      if ($body_class) {
+        $raw = strtr($body_class, $tokens);
+        $classes = preg_split('/\s+/', $raw);
+        if ($classes) {
+          foreach ($classes as $class) {
+            if ($class !== '') {
+              $variables['attributes']['class'][] = Html::escape($class);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements hook_preprocess_node().
+   *
+   * Adds custom node class.
+   */
+  #[Hook('preprocess_node')]
+  public function preprocessNode(array &$variables) {
+    if (isset($variables['node'])) {
+      $node = $variables['node'];
+      $type = \Drupal::entityTypeManager()->getStorage('node_type')->load($node->bundle());
+      $node_class = $type->getThirdPartySetting('node_id_class', 'node_class', '');
+      if ($node_class) {
+        $tokens = [
+          '{node_id}' => $node->id(),
+          '{node_title}' => node_id_class_generate_slug($node->getTitle()),
+          '{node_author_uid}' => $node->getOwnerId(),
+          '{bundle}' => $node->bundle(),
+        ];
+        $raw = strtr($node_class, $tokens);
+        $classes = preg_split('/\s+/', $raw);
+        if ($classes) {
+          foreach ($classes as $class) {
+            if ($class !== '') {
+              $variables['attributes']['class'][] = Html::escape($class);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    if ($route_name === 'help.page.node_id_class') {
+      return '<h2>' . $this->t('Node ID Class') . '</h2>' . '<p>' . $this->t('The Node ID Class module enables site builders to add dynamic CSS IDs and classes to the <code>&lt;body&gt;</code> element and node wrappers. You can use tokens such as {node_id}, {node_title}, {bundle}, and {node_author_uid} to generate dynamic, theme-friendly class names and IDs.') . '</p>' . '<h3>' . $this->t('Key Features') . '</h3>' . '<ul>' . '<li>' . $this->t('Add custom CSS Body ID to full node pages.') . '</li>' . '<li>' . $this->t('Add multiple CSS Body Classes.') . '</li>' . '<li>' . $this->t('Add multiple CSS Node Classes to node wrappers and Views listings.') . '</li>' . '<li>' . $this->t('Supports dynamic tokens for flexible theming: {node_id}, {node_title}, {bundle}, {node_author_uid}.') . '</li>' . '<li>' . $this->t('Inputs are validated and sanitized to prevent XSS or invalid markup.') . '</li>' . '</ul>';
+    }
+  }
+
+}
