commit 1ae50d2723b4b5a4867f212dd43a02fc64e1bbe0
Author: Erik Stielstra <erik@limoengroen.nl>
Date:   Thu Jun 25 11:05:42 2020 +0200

    Support error messages in fieldsets.

diff --git a/a11y_form_helpers.module b/a11y_form_helpers.module
index d28a8d9..6a37875 100644
--- a/a11y_form_helpers.module
+++ b/a11y_form_helpers.module
@@ -66,6 +66,21 @@ function a11y_form_helpers_theme_registry_alter(&$theme_registry) {
 
     $theme_registry['form_element']['theme path'] = $module_path;
   }
+
+  // Replace default theme fieldset.html.twig template from core.
+  if (strpos($theme_registry['fieldset']['theme path'], 'core/') === 0) {
+    $path = array_reverse(explode('/', $theme_registry['fieldset']['theme path']));
+    $module_path = drupal_get_path('module', 'a11y_form_helpers');
+
+    if (file_exists($module_path . '/templates/' . $path[0])) {
+      $theme_registry['fieldset']['path'] = $module_path . '/templates/' . $path[0];
+    }
+    else {
+      $theme_registry['fieldset']['path'] = $module_path . '/templates/system';
+    }
+
+    $theme_registry['fieldset']['theme path'] = $module_path;
+  }
 }
 
 /**
@@ -82,6 +97,19 @@ function a11y_form_helpers_preprocess_form_element(&$variables) {
 
 }
 
+/**
+ * Implements hook_preprocess_HOOK() for fieldset.
+ */
+function a11y_form_helpers_preprocess_fieldset(&$variables) {
+  $element = &$variables['element'];
+
+  // Add error data.
+  if (!empty($element['#errors']) && empty($element['#error_no_message'])) {
+    $variables['errors'] = $element['#errors'];
+    $variables['errormessage_id'] = $element['#id'] . '--errormessage';
+  }
+}
+
 /**
  * Implements hook_field_widget_third_party_settings_form().
  */
diff --git a/templates/claro/fieldset.html.twig b/templates/claro/fieldset.html.twig
new file mode 100644
index 0000000..a470f08
--- /dev/null
+++ b/templates/claro/fieldset.html.twig
@@ -0,0 +1,81 @@
+{#
+/**
+ * @file
+ * Theme override for a fieldset element and its children.
+ *
+ * @see template_preprocess_fieldset()
+ * @see claro_preprocess_fieldset()
+ */
+#}
+{%
+  set classes = [
+    'fieldset',
+    attributes.hasClass('fieldgroup') ? 'fieldset--group',
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'form-wrapper',
+  ]
+%}
+{%
+  set wrapper_classes = [
+    'fieldset__wrapper',
+    attributes.hasClass('fieldgroup') ? 'fieldset__wrapper--group',
+  ]
+%}
+{%
+  set legend_span_classes = [
+    'fieldset__label',
+    attributes.hasClass('fieldgroup') ? 'fieldset__label--group',
+    required ? 'js-form-required',
+    required ? 'form-required',
+  ]
+%}
+{%
+  set legend_classes = [
+    'fieldset__legend',
+    attributes.hasClass('fieldgroup') and not attributes.hasClass('form-composite') ? 'fieldset__legend--group',
+    attributes.hasClass('form-composite') ? 'fieldset__legend--composite',
+    title_display == 'invisible' ? 'fieldset__legend--invisible' : 'fieldset__legend--visible',
+  ]
+%}
+{%
+  set description_classes = [
+   'fieldset__description',
+  ]
+%}
+
+<fieldset{{ attributes.addClass(classes) }}>
+  {#  Always wrap fieldset legends in a <span> for CSS positioning. #}
+  {% if legend.title %}
+  <legend{{ legend.attributes.addClass(legend_classes) }}>
+    <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
+  </legend>
+  {% endif %}
+
+  <div{{ content_attributes.addClass(wrapper_classes) }}>
+    {% if inline_items %}
+      <div class="container-inline">
+    {% endif %}
+
+    {% if prefix %}
+      <span class="fieldset__prefix">{{ prefix }}</span>
+    {% endif %}
+    {{ children }}
+    {% if suffix %}
+      <span class="fieldset__suffix">{{ suffix }}</span>
+    {% endif %}
+    {% if errors %}
+      <div id="{{ errormessage_id }}" class="fieldset__error-message">
+        {{ errors }}
+      </div>
+    {% endif %}
+    {% if description.content %}
+      <div{{ description.attributes.addClass(description_classes) }}>{{ description.content }}</div>
+    {% endif %}
+
+    {% if inline_items %}
+      </div>
+    {% endif %}
+  </div>
+</fieldset>
diff --git a/templates/classy/fieldset.html.twig b/templates/classy/fieldset.html.twig
new file mode 100644
index 0000000..2284bcb
--- /dev/null
+++ b/templates/classy/fieldset.html.twig
@@ -0,0 +1,60 @@
+{#
+/**
+ * @file
+ * Theme override for a fieldset element and its children.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the fieldset element.
+ * - errors: (optional) Any errors for this fieldset element, may not be set.
+ * - required: Boolean indicating whether the fieldeset element is required.
+ * - legend: The legend element containing the following properties:
+ *   - title: Title of the fieldset, intended for use as the text of the legend.
+ *   - attributes: HTML attributes to apply to the legend.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the fieldset.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - children: The rendered child elements of the fieldset.
+ * - prefix: The content to add before the fieldset children.
+ * - suffix: The content to add after the fieldset children.
+ *
+ * @see template_preprocess_fieldset()
+ */
+#}
+{%
+  set classes = [
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'form-wrapper',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
+  {%
+    set legend_span_classes = [
+      'fieldset-legend',
+      required ? 'js-form-required',
+      required ? 'form-required',
+    ]
+  %}
+  {#  Always wrap fieldset legends in a <span> for CSS positioning. #}
+  <legend{{ legend.attributes }}>
+    <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
+  </legend>
+  <div class="fieldset-wrapper">
+    {% if errors %}
+    <div id="{{ errormessage_id }}" class="form-item--error-message">
+        <strong>{{ errors }}</strong>
+      </div>
+    {% endif %}
+    {% if prefix %}
+      <span class="field-prefix">{{ prefix }}</span>
+    {% endif %}
+    {{ children }}
+    {% if suffix %}
+      <span class="field-suffix">{{ suffix }}</span>
+    {% endif %}
+    {% if description.content %}
+      <div{{ description.attributes.addClass('description') }}>{{ description.content }}</div>
+    {% endif %}
+  </div>
+</fieldset>
diff --git a/templates/stable/fieldset.html.twig b/templates/stable/fieldset.html.twig
new file mode 100644
index 0000000..93197e3
--- /dev/null
+++ b/templates/stable/fieldset.html.twig
@@ -0,0 +1,61 @@
+{#
+/**
+ * @file
+ * Theme override for a fieldset element and its children.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the <fieldset> element.
+ * - errors: (optional) Any errors for this <fieldset> element, may not be set.
+ * - required: Boolean indicating whether the <fieldeset> element is required.
+ * - legend: The <legend> element containing the following properties:
+ *   - title: Title of the <fieldset>, intended for use as the text
+       of the <legend>.
+ *   - attributes: HTML attributes to apply to the <legend> element.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the <fieldset>.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - children: The rendered child elements of the <fieldset>.
+ * - prefix: The content to add before the <fieldset> children.
+ * - suffix: The content to add after the <fieldset> children.
+ *
+ * @see template_preprocess_fieldset()
+ */
+#}
+{%
+  set classes = [
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'form-wrapper',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
+  {%
+    set legend_span_classes = [
+      'fieldset-legend',
+      required ? 'js-form-required',
+      required ? 'form-required',
+    ]
+  %}
+  {#  Always wrap fieldset legends in a <span> for CSS positioning. #}
+  <legend{{ legend.attributes }}>
+    <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
+  </legend>
+  <div class="fieldset-wrapper">
+    {% if errors %}
+      <div id="{{ errormessage_id }}">
+        {{ errors }}
+      </div>
+    {% endif %}
+    {% if prefix %}
+      <span class="field-prefix">{{ prefix }}</span>
+    {% endif %}
+    {{ children }}
+    {% if suffix %}
+      <span class="field-suffix">{{ suffix }}</span>
+    {% endif %}
+    {% if description.content %}
+      <div{{ description.attributes.addClass('description') }}>{{ description.content }}</div>
+    {% endif %}
+  </div>
+</fieldset>
diff --git a/templates/system/fieldset.html.twig b/templates/system/fieldset.html.twig
new file mode 100644
index 0000000..cd47412
--- /dev/null
+++ b/templates/system/fieldset.html.twig
@@ -0,0 +1,63 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a fieldset element and its children.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the <fieldset> element.
+ * - errors: (optional) Any errors for this <fieldset> element, may not be set.
+ * - required: Boolean indicating whether the <fieldeset> element is required.
+ * - legend: The <legend> element containing the following properties:
+ *   - title: Title of the <fieldset>, intended for use as the text
+       of the <legend>.
+ *   - attributes: HTML attributes to apply to the <legend> element.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the <fieldset>.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - children: The rendered child elements of the <fieldset>.
+ * - prefix: The content to add before the <fieldset> children.
+ * - suffix: The content to add after the <fieldset> children.
+ *
+ * @see template_preprocess_fieldset()
+ *
+ * @ingroup themeable
+ */
+#}
+{%
+  set classes = [
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'form-wrapper',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
+  {%
+    set legend_span_classes = [
+      'fieldset-legend',
+      required ? 'js-form-required',
+      required ? 'form-required',
+    ]
+  %}
+  {#  Always wrap fieldset legends in a <span> for CSS positioning. #}
+  <legend{{ legend.attributes }}>
+    <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
+  </legend>
+  <div class="fieldset-wrapper">
+    {% if errors %}
+      <div id="{{ errormessage_id }}">
+        {{ errors }}
+      </div>
+    {% endif %}
+    {% if prefix %}
+      <span class="field-prefix">{{ prefix }}</span>
+    {% endif %}
+    {{ children }}
+    {% if suffix %}
+      <span class="field-suffix">{{ suffix }}</span>
+    {% endif %}
+    {% if description.content %}
+      <div{{ description.attributes.addClass('description') }}>{{ description.content }}</div>
+    {% endif %}
+  </div>
+</fieldset>
