diff --git a/config/install/toc_api.toc_type.default.yml b/config/install/toc_api.toc_type.default.yml
index 705ec78a9673d3aa4980ead230e8a123125db2fd..e4dddc2c715cac5c8132ca504367b941a5689f73 100644
--- a/config/install/toc_api.toc_type.default.yml
+++ b/config/install/toc_api.toc_type.default.yml
@@ -14,6 +14,8 @@ options:
   header_id: title
   header_id_prefix: section
   header_exclude_xpath: ''
+  wrapper: div
+  title_wrapper: h3
   top_label: 'Back to top'
   top_min: 2
   top_max: 2
diff --git a/config/install/toc_api.toc_type.full.yml b/config/install/toc_api.toc_type.full.yml
index dd671e8a53c4a23bde96b06f23637b75f61bf5a1..9218b8537b23de6e03bfcc52aeb20b1145ce2e47 100644
--- a/config/install/toc_api.toc_type.full.yml
+++ b/config/install/toc_api.toc_type.full.yml
@@ -14,6 +14,8 @@ options:
   header_id: title
   header_id_prefix: section
   header_exclude_xpath: ''
+  wrapper: div
+  title_wrapper: h3
   top_label: 'Back to top'
   top_min: 2
   top_max: 2
diff --git a/config/install/toc_api.toc_type.full_numbered.yml b/config/install/toc_api.toc_type.full_numbered.yml
index 61961c7f0710aa311d50bd40130d3fd58716b81a..5bfcaced9e78b99b28392645e0c81a517427e01e 100644
--- a/config/install/toc_api.toc_type.full_numbered.yml
+++ b/config/install/toc_api.toc_type.full_numbered.yml
@@ -14,6 +14,8 @@ options:
   header_id: title
   header_id_prefix: section
   header_exclude_xpath: ''
+  wrapper: div
+  title_wrapper: h3
   top_label: 'Back to top'
   top_min: 2
   top_max: 2
diff --git a/config/install/toc_api.toc_type.simple.yml b/config/install/toc_api.toc_type.simple.yml
index 20bfad37967a5c1dd1a940dd4c9befc2afec32d8..c4f6a318be950961f2ef2e48cb526d901e4b575f 100644
--- a/config/install/toc_api.toc_type.simple.yml
+++ b/config/install/toc_api.toc_type.simple.yml
@@ -14,6 +14,8 @@ options:
   header_id: title
   header_id_prefix: section
   header_exclude_xpath: ''
+  wrapper: div
+  title_wrapper: h3
   top_label: 'Back to top'
   top_min: 2
   top_max: 2
diff --git a/config/install/toc_api.toc_type.simple_numbered.yml b/config/install/toc_api.toc_type.simple_numbered.yml
index bcccb138e7affd3a3f8671905b0f216a9fec2d20..9ad46c2bb2436e0376c3d7fc395b12452150a934 100644
--- a/config/install/toc_api.toc_type.simple_numbered.yml
+++ b/config/install/toc_api.toc_type.simple_numbered.yml
@@ -14,6 +14,8 @@ options:
   header_id: title
   header_id_prefix: section
   header_exclude_xpath: ''
+  wrapper: div
+  title_wrapper: h3
   top_label: 'Back to top'
   top_min: 2
   top_max: 2
diff --git a/config/schema/toc_api.toc_type.schema.yml b/config/schema/toc_api.toc_type.schema.yml
index 19bdb585abff3c638d8cdf9f612e99d4107ef499..7500d669daba629f4dba5093336cb1469c798707 100644
--- a/config/schema/toc_api.toc_type.schema.yml
+++ b/config/schema/toc_api.toc_type.schema.yml
@@ -92,3 +92,9 @@ toc_api.toc_type.*:
               type: ignore
             h6:
               type: ignore
+    wrapper:
+      type: string
+      label: 'Wrapper element'
+    title_wrapper:
+      type: string
+      label: 'Title wrapper'
diff --git a/src/TocTypeForm.php b/src/TocTypeForm.php
index 9c1012e867387e32b4d0bf0aea5e1fc55622c044..a7ae28441fa781c47272bff14c650b6b2b6aecb7 100644
--- a/src/TocTypeForm.php
+++ b/src/TocTypeForm.php
@@ -141,6 +141,18 @@ class TocTypeForm extends EntityForm {
       '#type' => 'textfield',
       '#default_value' => $options['title'],
     ];
+    $form['options']['general']['title_wrapper'] = [
+      '#title' => $this->t('Wrapper element for title'),
+      '#type' => 'textfield',
+      '#default_value' => $options['title_wrapper'] ?? 'h3',
+      '#required' => TRUE,
+    ];
+    $form['options']['general']['wrapper'] = [
+      '#title' => $this->t('Wrapper element for table of contents'),
+      '#type' => 'textfield',
+      '#default_value' => $options['wrapper'] ?? 'div',
+      '#required' => TRUE,
+    ];
     // Hide block option since it is up to TOC submodule to decide how to
     // support it.
     $form['options']['general']['block'] = [
@@ -335,6 +347,23 @@ class TocTypeForm extends EntityForm {
     return $form;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state): void {
+    // Validate HTML tag names.
+    $elements = [
+      'title_wrapper',
+      'wrapper',
+    ];
+    foreach ($elements as $element) {
+      $tag_name = $form_state->getValue(['general', $element]);
+      if (!preg_match('/^[a-zA-Z0-9-]+$/', $tag_name)) {
+        $form_state->setErrorByName('general][' . $element, $this->t('Invalid HTML tag name.'));
+      }
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/templates/toc-tree.html.twig b/templates/toc-tree.html.twig
index 692ae77d2d2194668f196aeef899f02757f18970..e582d62423087f9c06382d6c39f685b4aacef703 100644
--- a/templates/toc-tree.html.twig
+++ b/templates/toc-tree.html.twig
@@ -6,6 +6,7 @@
  * Returns HTML for a nested list representation of a Table of contents..
  *
  * Available variables:
+ * - options: An array of configuration options.
  * - tree: A nested list of header items. Each header item contains:
  *   - list_tag: HTML tag for the list.
  *   - list_attributes: HTML attributes for the list.
@@ -22,17 +23,18 @@
   @see http://twig.sensiolabs.org/doc/tags/macro.html
 #}
 {% import _self as toc_api_tree %}
-{% set classes = ['toc', 'toc-tree'] %}
 
-<div{{ attributes.addClass(classes) }}>
+{% set wrapper = options.wrapper ?? 'div' %}
+<{{ wrapper }}{{ attributes }}>
 
   {% if tree.title and not options.block %}
-    <h3>{{ tree.title }}</h3>
+    {% set title_wrapper = options.title_wrapper ?? 'h3' %}
+    <{{ title_wrapper }}>{{ tree.title }}</{{ title_wrapper }}>
   {% endif %}
 
   {{ toc_api_tree.tree_links(tree) }}
 
-</div>
+</{{ wrapper }}>
 
 {% macro tree_links(item) %}
   {% import _self as toc_api_tree %}
diff --git a/toc_api.module b/toc_api.module
index cdd60e1d214d76dccba0888edd4b219cad7296a7..012f1ea9da6ce7d7cadb9992dcca2d2d83e88d27 100755
--- a/toc_api.module
+++ b/toc_api.module
@@ -118,6 +118,11 @@ function template_preprocess_toc_tree(&$variables) {
 
   $variables['options'] = $toc->getOptions();
 
+  // Add default classes.
+  $variables['attributes']['class'] = (array) $variables['attributes']['class'];
+  $variables['attributes']['class'][] = 'toc';
+  $variables['attributes']['class'][] = 'toc-tree';
+
   $variables['attributes'] = new Attribute($variables['attributes']);
 
   $variables['#attached']['library'][] = 'toc_api/toc.tree';