Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SPIKE] Prevent components being initialised more than once #4561

Closed
wants to merge 3 commits into from

Conversation

colinrotherham
Copy link
Contributor

@colinrotherham colinrotherham commented Dec 12, 2023

Quick spike to discuss adding data-module-init to components when they're initialised

This can be used to prevent components being initialised more than once

Closes: #1127

Checking if previously initialised

I've added a new checkInitialised($module) method on the base class

When the data attribute data-module-init is already set we can throw an error

  constructor($module) {
    this.checkSupport()
+   this.checkInitialised($module)
+
+   // Mark component as initialised in HTML
+   $module?.setAttribute('data-module-init', 'true')
  }

Copy link

github-actions bot commented Dec 12, 2023

📋 Stats

File sizes

File Size
dist/govuk-frontend-development.min.css 112.86 KiB
dist/govuk-frontend-development.min.js 38.9 KiB
packages/govuk-frontend/dist/govuk/all.bundle.js 79.31 KiB
packages/govuk-frontend/dist/govuk/all.bundle.mjs 74.54 KiB
packages/govuk-frontend/dist/govuk/all.mjs 3.86 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs 622 B
packages/govuk-frontend/dist/govuk/govuk-frontend.min.css 112.85 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend.min.js 38.89 KiB
packages/govuk-frontend/dist/govuk/i18n.mjs 5.38 KiB

Modules

File Size (bundled) Size (minified)
all.mjs 70.87 KiB 37.12 KiB
accordion.mjs 22.26 KiB 12.75 KiB
button.mjs 5.25 KiB 2.49 KiB
character-count.mjs 21.83 KiB 9.78 KiB
checkboxes.mjs 6.42 KiB 3.16 KiB
error-summary.mjs 7.16 KiB 3.26 KiB
exit-this-page.mjs 16.63 KiB 9.19 KiB
header.mjs 5.05 KiB 2.94 KiB
notification-banner.mjs 5.52 KiB 2.42 KiB
radios.mjs 5.42 KiB 2.71 KiB
skip-link.mjs 4.97 KiB 2.51 KiB
tabs.mjs 10.72 KiB 6.45 KiB

View stats and visualisations on the review app


Action run for 5574dfa

Copy link

github-actions bot commented Dec 12, 2023

JavaScript changes to npm package

diff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
index 32ea76aa4..95f38306e 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
@@ -105,9 +105,19 @@ class ElementError extends GOVUKFrontendError {
         super(e), this.name = "ElementError"
     }
 }
+class InitError extends GOVUKFrontendError {
+    constructor(t) {
+        super(`Root element (\`$module\`) already initialised (\`${t.getAttribute("data-module")}\`)`), this.name = "InitError"
+    }
+}
 class GOVUKFrontendComponent {
-    constructor() {
-        this.checkSupport()
+    constructor(t) {
+        this.checkSupport(), this.checkInitialised(t), null == t || t.setAttribute("data-module-init", "true")
+    }
+    checkInitialised(t) {
+        if (t && function(t) {
+                return t instanceof HTMLElement && "moduleInit" in t.dataset
+            }(t)) throw new InitError(t)
     }
     checkSupport() {
         if (!isSupported()) throw new SupportError
@@ -191,7 +201,7 @@ I18n.pluralRulesMap = {
 };
 class Accordion extends GOVUKFrontendComponent {
     constructor(e, n = {}) {
-        if (super(), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.controlsClass = "govuk-accordion__controls", this.showAllClass = "govuk-accordion__show-all", this.showAllTextClass = "govuk-accordion__show-all-text", this.sectionClass = "govuk-accordion__section", this.sectionExpandedClass = "govuk-accordion__section--expanded", this.sectionButtonClass = "govuk-accordion__section-button", this.sectionHeaderClass = "govuk-accordion__section-header", this.sectionHeadingClass = "govuk-accordion__section-heading", this.sectionHeadingDividerClass = "govuk-accordion__section-heading-divider", this.sectionHeadingTextClass = "govuk-accordion__section-heading-text", this.sectionHeadingTextFocusClass = "govuk-accordion__section-heading-text-focus", this.sectionShowHideToggleClass = "govuk-accordion__section-toggle", this.sectionShowHideToggleFocusClass = "govuk-accordion__section-toggle-focus", this.sectionShowHideTextClass = "govuk-accordion__section-toggle-text", this.upChevronIconClass = "govuk-accordion-nav__chevron", this.downChevronIconClass = "govuk-accordion-nav__chevron--down", this.sectionSummaryClass = "govuk-accordion__section-summary", this.sectionSummaryFocusClass = "govuk-accordion__section-summary-focus", this.sectionContentClass = "govuk-accordion__section-content", this.$sections = void 0, this.browserSupportsSessionStorage = !1, this.$showAllButton = null, this.$showAllIcon = null, this.$showAllText = null, !(e instanceof HTMLElement)) throw new ElementError({
+        if (super(e), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.controlsClass = "govuk-accordion__controls", this.showAllClass = "govuk-accordion__show-all", this.showAllTextClass = "govuk-accordion__show-all-text", this.sectionClass = "govuk-accordion__section", this.sectionExpandedClass = "govuk-accordion__section--expanded", this.sectionButtonClass = "govuk-accordion__section-button", this.sectionHeaderClass = "govuk-accordion__section-header", this.sectionHeadingClass = "govuk-accordion__section-heading", this.sectionHeadingDividerClass = "govuk-accordion__section-heading-divider", this.sectionHeadingTextClass = "govuk-accordion__section-heading-text", this.sectionHeadingTextFocusClass = "govuk-accordion__section-heading-text-focus", this.sectionShowHideToggleClass = "govuk-accordion__section-toggle", this.sectionShowHideToggleFocusClass = "govuk-accordion__section-toggle-focus", this.sectionShowHideTextClass = "govuk-accordion__section-toggle-text", this.upChevronIconClass = "govuk-accordion-nav__chevron", this.downChevronIconClass = "govuk-accordion-nav__chevron--down", this.sectionSummaryClass = "govuk-accordion__section-summary", this.sectionSummaryFocusClass = "govuk-accordion__section-summary-focus", this.sectionContentClass = "govuk-accordion__section-content", this.$sections = void 0, this.browserSupportsSessionStorage = !1, this.$showAllButton = null, this.$showAllIcon = null, this.$showAllText = null, !(e instanceof HTMLElement)) throw new ElementError({
             componentName: "Accordion",
             element: e,
             identifier: "Root element (`$module`)"
@@ -351,7 +361,7 @@ const t = {
 };
 class Button extends GOVUKFrontendComponent {
     constructor(t, e = {}) {
-        if (super(), this.$module = void 0, this.config = void 0, this.debounceFormSubmitTimer = null, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.config = void 0, this.debounceFormSubmitTimer = null, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Button",
             element: t,
             identifier: "Root element (`$module`)"
@@ -379,7 +389,7 @@ Button.moduleName = "govuk-button", Button.defaults = Object.freeze({
 class CharacterCount extends GOVUKFrontendComponent {
     constructor(t, e = {}) {
         var n, i;
-        if (super(), this.$module = void 0, this.$textarea = void 0, this.$visibleCountMessage = void 0, this.$screenReaderCountMessage = void 0, this.lastInputTimestamp = null, this.lastInputValue = "", this.valueChecker = null, this.config = void 0, this.i18n = void 0, this.maxLength = void 0, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.$textarea = void 0, this.$visibleCountMessage = void 0, this.$screenReaderCountMessage = void 0, this.lastInputTimestamp = null, this.lastInputValue = "", this.valueChecker = null, this.config = void 0, this.i18n = void 0, this.maxLength = void 0, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Character count",
             element: t,
             identifier: "Root element (`$module`)"
@@ -517,7 +527,7 @@ CharacterCount.moduleName = "govuk-character-count", CharacterCount.defaults = O
 });
 class Checkboxes extends GOVUKFrontendComponent {
     constructor(t) {
-        if (super(), this.$module = void 0, this.$inputs = void 0, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.$inputs = void 0, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Checkboxes",
             element: t,
             identifier: "Root element (`$module`)"
@@ -570,7 +580,7 @@ class Checkboxes extends GOVUKFrontendComponent {
 Checkboxes.moduleName = "govuk-checkboxes";
 class ErrorSummary extends GOVUKFrontendComponent {
     constructor(t, e = {}) {
-        if (super(), this.$module = void 0, this.config = void 0, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.config = void 0, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Error summary",
             element: t,
             identifier: "Root element (`$module`)"
@@ -615,7 +625,7 @@ ErrorSummary.moduleName = "govuk-error-summary", ErrorSummary.defaults = Object.
 });
 class ExitThisPage extends GOVUKFrontendComponent {
     constructor(t, e = {}) {
-        if (super(), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.$button = void 0, this.$skiplinkButton = null, this.$updateSpan = null, this.$indicatorContainer = null, this.$overlay = null, this.keypressCounter = 0, this.lastKeyWasModified = !1, this.timeoutTime = 5e3, this.keypressTimeoutId = null, this.timeoutMessageId = null, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.$button = void 0, this.$skiplinkButton = null, this.$updateSpan = null, this.$indicatorContainer = null, this.$overlay = null, this.keypressCounter = 0, this.lastKeyWasModified = !1, this.timeoutTime = 5e3, this.keypressTimeoutId = null, this.timeoutMessageId = null, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Exit this page",
             element: t,
             identifier: "Root element (`$module`)"
@@ -686,7 +696,7 @@ ExitThisPage.moduleName = "govuk-exit-this-page", ExitThisPage.defaults = Object
 });
 class Header extends GOVUKFrontendComponent {
     constructor(t) {
-        if (super(), this.$module = void 0, this.$menuButton = void 0, this.$menu = void 0, this.menuIsOpen = !1, this.mql = null, !t) throw new ElementError({
+        if (super(t), this.$module = void 0, this.$menuButton = void 0, this.$menu = void 0, this.menuIsOpen = !1, this.mql = null, !t) throw new ElementError({
             componentName: "Header",
             element: t,
             identifier: "Root element (`$module`)"
@@ -725,7 +735,7 @@ class Header extends GOVUKFrontendComponent {
 Header.moduleName = "govuk-header";
 class NotificationBanner extends GOVUKFrontendComponent {
     constructor(t, e = {}) {
-        if (super(), this.$module = void 0, this.config = void 0, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.config = void 0, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Notification banner",
             element: t,
             identifier: "Root element (`$module`)"
@@ -738,7 +748,7 @@ NotificationBanner.moduleName = "govuk-notification-banner", NotificationBanner.
 });
 class Radios extends GOVUKFrontendComponent {
     constructor(t) {
-        if (super(), this.$module = void 0, this.$inputs = void 0, !(t instanceof HTMLElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, this.$inputs = void 0, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Radios",
             element: t,
             identifier: "Root element (`$module`)"
@@ -787,7 +797,7 @@ Radios.moduleName = "govuk-radios";
 class SkipLink extends GOVUKFrontendComponent {
     constructor(t) {
         var e;
-        if (super(), this.$module = void 0, !(t instanceof HTMLAnchorElement)) throw new ElementError({
+        if (super(t), this.$module = void 0, !(t instanceof HTMLAnchorElement)) throw new ElementError({
             componentName: "Skip link",
             element: t,
             expectedType: "HTMLAnchorElement",
@@ -824,7 +834,7 @@ class SkipLink extends GOVUKFrontendComponent {
 SkipLink.moduleName = "govuk-skip-link";
 class Tabs extends GOVUKFrontendComponent {
     constructor(t) {
-        if (super(), this.$module = void 0, this.$tabs = void 0, this.$tabList = void 0, this.$tabListItems = void 0, this.jsHiddenClass = "govuk-tabs__panel--hidden", this.changingHash = !1, this.boundTabClick = void 0, this.boundTabKeydown = void 0, this.boundOnHashChange = void 0, this.mql = null, !t) throw new ElementError({
+        if (super(t), this.$module = void 0, this.$tabs = void 0, this.$tabList = void 0, this.$tabListItems = void 0, this.jsHiddenClass = "govuk-tabs__panel--hidden", this.changingHash = !1, this.boundTabClick = void 0, this.boundTabKeydown = void 0, this.boundOnHashChange = void 0, this.mql = null, !t) throw new ElementError({
             componentName: "Tabs",
             element: t,
             identifier: "Root element (`$module`)"

Action run for 5574dfa

Copy link

github-actions bot commented Dec 12, 2023

Other changes to npm package

diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.js b/packages/govuk-frontend/dist/govuk/all.bundle.js
index 319a2fe70..f43827220 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.js
@@ -83,6 +83,9 @@
     (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
     $element.focus();
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -188,10 +191,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -407,7 +424,7 @@
      * @param {AccordionConfig} [config] - Accordion config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.i18n = void 0;
@@ -746,7 +763,7 @@
      * @param {ButtonConfig} [config] - Button config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.debounceFormSubmitTimer = null;
@@ -822,7 +839,7 @@
      */
     constructor($module, config = {}) {
       var _ref, _this$config$maxwords;
-      super();
+      super($module);
       this.$module = void 0;
       this.$textarea = void 0;
       this.$visibleCountMessage = void 0;
@@ -1105,7 +1122,7 @@
      * @param {Element | null} $module - HTML element to use for checkboxes
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$inputs = void 0;
       if (!($module instanceof HTMLElement)) {
@@ -1213,7 +1230,7 @@
      * @param {ErrorSummaryConfig} [config] - Error summary config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       if (!($module instanceof HTMLElement)) {
@@ -1305,7 +1322,7 @@
      * @param {ExitThisPageConfig} [config] - Exit This Page config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.i18n = void 0;
@@ -1523,7 +1540,7 @@
      * @param {Element | null} $module - HTML element to use for header
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$menuButton = void 0;
       this.$menu = void 0;
@@ -1612,7 +1629,7 @@
      * @param {NotificationBannerConfig} [config] - Notification banner config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       if (!($module instanceof HTMLElement)) {
@@ -1665,7 +1682,7 @@
      * @param {Element | null} $module - HTML element to use for radios
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$inputs = void 0;
       if (!($module instanceof HTMLElement)) {
@@ -1750,7 +1767,7 @@
      */
     constructor($module) {
       var _this$$module$getAttr;
-      super();
+      super($module);
       this.$module = void 0;
       if (!($module instanceof HTMLAnchorElement)) {
         throw new ElementError({
@@ -1806,7 +1823,7 @@
      * @param {Element | null} $module - HTML element to use for tabs
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$tabs = void 0;
       this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.mjs b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
index 1e8dbc738..beb30cbd4 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
@@ -77,6 +77,9 @@ function setFocus($element, options = {}) {
   (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
   $element.focus();
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -182,10 +185,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -401,7 +418,7 @@ class Accordion extends GOVUKFrontendComponent {
    * @param {AccordionConfig} [config] - Accordion config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
@@ -740,7 +757,7 @@ class Button extends GOVUKFrontendComponent {
    * @param {ButtonConfig} [config] - Button config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.debounceFormSubmitTimer = null;
@@ -816,7 +833,7 @@ class CharacterCount extends GOVUKFrontendComponent {
    */
   constructor($module, config = {}) {
     var _ref, _this$config$maxwords;
-    super();
+    super($module);
     this.$module = void 0;
     this.$textarea = void 0;
     this.$visibleCountMessage = void 0;
@@ -1099,7 +1116,7 @@ class Checkboxes extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for checkboxes
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
@@ -1207,7 +1224,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
    * @param {ErrorSummaryConfig} [config] - Error summary config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
@@ -1299,7 +1316,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
    * @param {ExitThisPageConfig} [config] - Exit This Page config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
@@ -1517,7 +1534,7 @@ class Header extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for header
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$menuButton = void 0;
     this.$menu = void 0;
@@ -1606,7 +1623,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
    * @param {NotificationBannerConfig} [config] - Notification banner config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
@@ -1659,7 +1676,7 @@ class Radios extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for radios
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
@@ -1744,7 +1761,7 @@ class SkipLink extends GOVUKFrontendComponent {
    */
   constructor($module) {
     var _this$$module$getAttr;
-    super();
+    super($module);
     this.$module = void 0;
     if (!($module instanceof HTMLAnchorElement)) {
       throw new ElementError({
@@ -1800,7 +1817,7 @@ class Tabs extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for tabs
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$tabs = void 0;
     this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/common/index.mjs b/packages/govuk-frontend/dist/govuk/common/index.mjs
index 1d272c1ba..47f86031f 100644
--- a/packages/govuk-frontend/dist/govuk/common/index.mjs
+++ b/packages/govuk-frontend/dist/govuk/common/index.mjs
@@ -75,6 +75,9 @@ function setFocus($element, options = {}) {
   (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
   $element.focus();
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -115,5 +118,5 @@ function validateConfig(schema, config) {
  * @property {string} errorMessage - Error message when required config fields not provided
  */
 
-export { extractConfigByNamespace, getBreakpoint, getFragmentFromUrl, isSupported, mergeConfigs, setFocus, validateConfig };
+export { extractConfigByNamespace, getBreakpoint, getFragmentFromUrl, isInitialised, isSupported, mergeConfigs, setFocus, validateConfig };
 //# sourceMappingURL=index.mjs.map
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
index d5dca973f..a17a9bcd2 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
@@ -43,6 +43,9 @@
     }
     return newObject;
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -124,10 +127,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -343,7 +360,7 @@
      * @param {AccordionConfig} [config] - Accordion config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
index eecebe24c..436e0a87a 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
@@ -37,6 +37,9 @@ function extractConfigByNamespace(configObject, namespace) {
   }
   return newObject;
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -118,10 +121,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -337,7 +354,7 @@ class Accordion extends GOVUKFrontendComponent {
    * @param {AccordionConfig} [config] - Accordion config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
index 1ccea5293..194cbec70 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
@@ -24,7 +24,7 @@ class Accordion extends GOVUKFrontendComponent {
    * @param {AccordionConfig} [config] - Accordion config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
index e8db70624..5c7b06360 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
@@ -29,6 +29,9 @@
     }
     return formattedConfigObject;
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -110,10 +113,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -135,7 +152,7 @@
      * @param {ButtonConfig} [config] - Button config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
index 5e00ee6d9..12889ed70 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
@@ -23,6 +23,9 @@ function mergeConfigs(...configObjects) {
   }
   return formattedConfigObject;
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -104,10 +107,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -129,7 +146,7 @@ class Button extends GOVUKFrontendComponent {
    * @param {ButtonConfig} [config] - Button config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.mjs b/packages/govuk-frontend/dist/govuk/components/button/button.mjs
index 541e56fab..bc660a9db 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.mjs
@@ -16,7 +16,7 @@ class Button extends GOVUKFrontendComponent {
    * @param {ButtonConfig} [config] - Button config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
index 482acde8d..5ee8e88b0 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
@@ -48,6 +48,9 @@
     }
     return newObject;
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -153,10 +156,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -371,7 +388,7 @@
      */
     constructor($module, config = {}) {
       var _ref, _this$config$maxwords;
-      super();
+      super($module);
       this.$module = void 0;
       this.$textarea = void 0;
       this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
index 8fcb8512d..eda6beabf 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
@@ -42,6 +42,9 @@ function extractConfigByNamespace(configObject, namespace) {
   }
   return newObject;
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -147,10 +150,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -365,7 +382,7 @@ class CharacterCount extends GOVUKFrontendComponent {
    */
   constructor($module, config = {}) {
     var _ref, _this$config$maxwords;
-    super();
+    super($module);
     this.$module = void 0;
     this.$textarea = void 0;
     this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
index 953feb6f5..9a0e3c1bd 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
@@ -24,7 +24,7 @@ class CharacterCount extends GOVUKFrontendComponent {
    */
   constructor($module, config = {}) {
     var _ref, _this$config$maxwords;
-    super();
+    super($module);
     this.$module = void 0;
     this.$textarea = void 0;
     this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
index cd1ad83e7..3b919020c 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
@@ -39,7 +39,17 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -63,8 +73,15 @@
    */
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -94,7 +111,7 @@
      * @param {Element | null} $module - HTML element to use for checkboxes
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$inputs = void 0;
       if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
index e526485d6..340d865ec 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
@@ -33,7 +33,17 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -57,8 +67,15 @@ function isSupported($scope = document.body) {
  */
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -88,7 +105,7 @@ class Checkboxes extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for checkboxes
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
index 53cc4a7a7..8173d1c2c 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
@@ -22,7 +22,7 @@ class Checkboxes extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for checkboxes
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
index 649a5eb30..fa4ae2bcb 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
@@ -59,6 +59,9 @@
     (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
     $element.focus();
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -140,10 +143,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -166,7 +183,7 @@
      * @param {ErrorSummaryConfig} [config] - Error summary config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
index 02bf81818..c0a5a9279 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
@@ -53,6 +53,9 @@ function setFocus($element, options = {}) {
   (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
   $element.focus();
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -134,10 +137,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -160,7 +177,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
    * @param {ErrorSummaryConfig} [config] - Error summary config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
index f0e343e1b..6a98f96d4 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
@@ -17,7 +17,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
    * @param {ErrorSummaryConfig} [config] - Error summary config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
index 4d726b847..3253a5034 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
@@ -43,6 +43,9 @@
     }
     return newObject;
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -124,10 +127,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -334,7 +351,7 @@
      * @param {ExitThisPageConfig} [config] - Exit This Page config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
index a8e072477..903b6f9bd 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
@@ -37,6 +37,9 @@ function extractConfigByNamespace(configObject, namespace) {
   }
   return newObject;
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -118,10 +121,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -328,7 +345,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
    * @param {ExitThisPageConfig} [config] - Exit This Page config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
index fa157c93e..5fa220681 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
@@ -15,7 +15,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
    * @param {ExitThisPageConfig} [config] - Exit This Page config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
index ee3b1e1c6..18284296d 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
@@ -12,6 +12,9 @@
       value: value || undefined
     };
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -69,10 +72,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -94,7 +111,7 @@
      * @param {Element | null} $module - HTML element to use for header
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$menuButton = void 0;
       this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
index 98e82f86d..f0e941155 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
@@ -6,6 +6,9 @@ function getBreakpoint(name) {
     value: value || undefined
   };
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -63,10 +66,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -88,7 +105,7 @@ class Header extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for header
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$menuButton = void 0;
     this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.mjs b/packages/govuk-frontend/dist/govuk/components/header/header.mjs
index cd6832271..a464c6b1f 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.mjs
@@ -15,7 +15,7 @@ class Header extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for header
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$menuButton = void 0;
     this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
index dbe944a6a..1518e3ae5 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
@@ -53,6 +53,9 @@
     (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
     $element.focus();
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -134,10 +137,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -157,7 +174,7 @@
      * @param {NotificationBannerConfig} [config] - Notification banner config
      */
     constructor($module, config = {}) {
-      super();
+      super($module);
       this.$module = void 0;
       this.config = void 0;
       if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
index f0fcf2532..ebbeb93ec 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
@@ -47,6 +47,9 @@ function setFocus($element, options = {}) {
   (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
   $element.focus();
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -128,10 +131,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -151,7 +168,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
    * @param {NotificationBannerConfig} [config] - Notification banner config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
index 1af8f3d96..1941f874a 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
@@ -14,7 +14,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
    * @param {NotificationBannerConfig} [config] - Notification banner config
    */
   constructor($module, config = {}) {
-    super();
+    super($module);
     this.$module = void 0;
     this.config = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
index 11cb7cbe4..c32f67e71 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
@@ -39,7 +39,17 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -63,8 +73,15 @@
    */
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -94,7 +111,7 @@
      * @param {Element | null} $module - HTML element to use for radios
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$inputs = void 0;
       if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
index 076d273b2..b69c51971 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
@@ -33,7 +33,17 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -57,8 +67,15 @@ function isSupported($scope = document.body) {
  */
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -88,7 +105,7 @@ class Radios extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for radios
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs b/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
index ed29c7b0a..f74cefb64 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
@@ -22,7 +22,7 @@ class Radios extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for radios
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$inputs = void 0;
     if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
index 03f8c198f..2d90ac01b 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
@@ -34,6 +34,9 @@
     (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
     $element.focus();
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -91,10 +94,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -117,7 +134,7 @@
      */
     constructor($module) {
       var _this$$module$getAttr;
-      super();
+      super($module);
       this.$module = void 0;
       if (!($module instanceof HTMLAnchorElement)) {
         throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
index 8386205c1..74badc208 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
@@ -28,6 +28,9 @@ function setFocus($element, options = {}) {
   (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
   $element.focus();
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -85,10 +88,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -111,7 +128,7 @@ class SkipLink extends GOVUKFrontendComponent {
    */
   constructor($module) {
     var _this$$module$getAttr;
-    super();
+    super($module);
     this.$module = void 0;
     if (!($module instanceof HTMLAnchorElement)) {
       throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
index 03fb0498c..90e6fc436 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
@@ -16,7 +16,7 @@ class SkipLink extends GOVUKFrontendComponent {
    */
   constructor($module) {
     var _this$$module$getAttr;
-    super();
+    super($module);
     this.$module = void 0;
     if (!($module instanceof HTMLAnchorElement)) {
       throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
index 8b0bdb9c0..7a9306c81 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
@@ -18,6 +18,9 @@
       value: value || undefined
     };
   }
+  function isInitialised($module) {
+    return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+  }
   function isSupported($scope = document.body) {
     if (!$scope) {
       return false;
@@ -75,10 +78,24 @@
       this.name = 'ElementError';
     }
   }
+  class InitError extends GOVUKFrontendError {
+    constructor($module) {
+      const moduleName = $module.getAttribute('data-module');
+      super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+      this.name = 'InitError';
+    }
+  }
 
   class GOVUKFrontendComponent {
-    constructor() {
+    constructor($module) {
       this.checkSupport();
+      this.checkInitialised($module);
+      $module == null || $module.setAttribute('data-module-init', 'true');
+    }
+    checkInitialised($module) {
+      if ($module && isInitialised($module)) {
+        throw new InitError($module);
+      }
     }
     checkSupport() {
       if (!isSupported()) {
@@ -97,7 +114,7 @@
      * @param {Element | null} $module - HTML element to use for tabs
      */
     constructor($module) {
-      super();
+      super($module);
       this.$module = void 0;
       this.$tabs = void 0;
       this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
index db1378320..d9f6da576 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
@@ -12,6 +12,9 @@ function getBreakpoint(name) {
     value: value || undefined
   };
 }
+function isInitialised($module) {
+  return $module instanceof HTMLElement && 'moduleInit' in $module.dataset;
+}
 function isSupported($scope = document.body) {
   if (!$scope) {
     return false;
@@ -69,10 +72,24 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {
@@ -91,7 +108,7 @@ class Tabs extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for tabs
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$tabs = void 0;
     this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
index 39cd49970..f3603e2cb 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
@@ -12,7 +12,7 @@ class Tabs extends GOVUKFrontendComponent {
    * @param {Element | null} $module - HTML element to use for tabs
    */
   constructor($module) {
-    super();
+    super($module);
     this.$module = void 0;
     this.$tabs = void 0;
     this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/errors/index.mjs b/packages/govuk-frontend/dist/govuk/errors/index.mjs
index 9a0f05478..d758755ee 100644
--- a/packages/govuk-frontend/dist/govuk/errors/index.mjs
+++ b/packages/govuk-frontend/dist/govuk/errors/index.mjs
@@ -39,6 +39,13 @@ class ElementError extends GOVUKFrontendError {
     this.name = 'ElementError';
   }
 }
+class InitError extends GOVUKFrontendError {
+  constructor($module) {
+    const moduleName = $module.getAttribute('data-module');
+    super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`);
+    this.name = 'InitError';
+  }
+}
 
-export { ConfigError, ElementError, GOVUKFrontendError, SupportError };
+export { ConfigError, ElementError, GOVUKFrontendError, InitError, SupportError };
 //# sourceMappingURL=index.mjs.map
diff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs b/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
index 79a580f74..612a33544 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
@@ -1,9 +1,16 @@
-import { isSupported } from './common/index.mjs';
-import { SupportError } from './errors/index.mjs';
+import { isInitialised, isSupported } from './common/index.mjs';
+import { InitError, SupportError } from './errors/index.mjs';
 
 class GOVUKFrontendComponent {
-  constructor() {
+  constructor($module) {
     this.checkSupport();
+    this.checkInitialised($module);
+    $module == null || $module.setAttribute('data-module-init', 'true');
+  }
+  checkInitialised($module) {
+    if ($module && isInitialised($module)) {
+      throw new InitError($module);
+    }
   }
   checkSupport() {
     if (!isSupported()) {

Action run for 5574dfa

@colinrotherham colinrotherham changed the base branch from main to init-double February 19, 2024 19:11
Base automatically changed from init-double to main February 20, 2024 17:24
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-4561 March 8, 2024 15:57 Inactive
@querkmachine
Copy link
Member

Closing for housekeeping reasons, as this spike seems unlikely to be resolved at this time.

Fixing the multiple initialisation issue is still on our radar and is something we would like to resolve in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Investigate components being initialised more than once
3 participants