diff --git a/src/servala/frontend/templates/includes/tabbed_fieldset_form.html b/src/servala/frontend/templates/includes/tabbed_fieldset_form.html
index 97e336e..d07b4e3 100644
--- a/src/servala/frontend/templates/includes/tabbed_fieldset_form.html
+++ b/src/servala/frontend/templates/includes/tabbed_fieldset_form.html
@@ -144,6 +144,7 @@
value="{% if form_submit_label %}{{ form_submit_label }}{% else %}{% translate "Save" %}{% endif %}" />
+
{% if form %}
{% endif %}
diff --git a/src/servala/static/js/bootstrap-tabs.js b/src/servala/static/js/bootstrap-tabs.js
new file mode 100644
index 0000000..d382475
--- /dev/null
+++ b/src/servala/static/js/bootstrap-tabs.js
@@ -0,0 +1,30 @@
+// Bootstrap 5 automatically initializes tabs with data-bs-toggle="tab"
+// but we need to ensure they work after HTMX swaps
+(function() {
+ 'use strict';
+
+ const initBootstrapTabs = () => {
+ const customTabList = document.querySelectorAll('#myTab button[data-bs-toggle="tab"]');
+ customTabList.forEach(function(tabButton) {
+ new bootstrap.Tab(tabButton);
+ });
+
+ const expertTabList = document.querySelectorAll('#expertTab button[data-bs-toggle="tab"]');
+ expertTabList.forEach(function(tabButton) {
+ new bootstrap.Tab(tabButton);
+ });
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initBootstrapTabs);
+ } else {
+ initBootstrapTabs();
+ }
+
+ document.addEventListener('htmx:afterSwap', function(event) {
+ if (event.detail.target.id === 'service-form' ||
+ event.detail.target.classList.contains('crd-form')) {
+ initBootstrapTabs();
+ }
+ });
+})();