Problem/Motivation

In our project, we use field group to create horizontal tabs for the node edit form. So we have the following tabs
- Core details (default open, #edit-group-core-details)
- Content components (closed, #edit-group-content-components)
- Others (closed #edit-group-others)

When we open the node edit page, the tab defaults to 'Core details' which is expected. When we open the page with anchor like '/node/add/page#edit-group-content-components', the second tab is expected to be activated by default.

This is working in ver 8.x-1.0. However this is broken after field_group has been upgraded from ver 1.0 to 3.1. The Drupal version is 8.9.17

Steps to reproduce

- install field_group 3.1
- add horizontal tabs with
- Core details (default open, #edit-group-core-details)
- Content components (closed, #edit-group-content-components)
- Others (closed #edit-group-others)
- add dummy fields to those group and save
- open page to check the first tab should be activated
- open page with anchor to check the second tab should be activated but not

Proposed resolution

I have checked that the default value has been added to the hidden input and it always output a default value in HTML changed by #3066522: Wrong default tab on page load.

So here is the html of the hidden input when we use ver 1.0

<input class="horizontal-tabs-active-tab" type="hidden" />

Here is the html of the hidden input when we use ver 3.1

<input class="horizontal-tabs-active-tab" data-drupal-selector="edit-group-tabs-group-tabs-active-tab" type="hidden" name="group_tabs[group_tabs__active_tab]" value="edit-group-core-details" />

The logic to find tab_focus is
1. check default value from hidden input
2. if no default value check URL fragment
3. if the default value is found, make it focused

As the default value is always provided in step 1, so activating link from URL fragment does not happen anymore.

Ideally, activating link fragment should take precedence over default tab.

Remaining tasks

N/A

User interface changes

N/A

API changes

N/A

Data model changes

N/A

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

eric.chenchao created an issue. See original summary.

eric.chenchao’s picture

Status: Active » Needs review
eric.chenchao’s picture

Here are two patches for 3.x and 3.1

deepalij’s picture

Able to reproduce the issue by using the steps in the IS.
Tried to apply patch #4 on drupal 10.1.x-dev with field_group 8.x-3.x
But the patch failed to apply.
See the error below:

Checking patch formatters/tabs/horizontal-tabs.js...
error: while searching for:

        var $this = $(this).addClass('horizontal-tabs-panes');
        var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
        var tab_focus;

        // Check if there are some details that can be converted to horizontal-tabs

error: patch failed: formatters/tabs/horizontal-tabs.js:30
error: formatters/tabs/horizontal-tabs.js: patch does not apply
Michael Blessing’s picture

StatusFileSize
new2.12 KB

Here is a rerolled version of the patch in #4 for the 3.4 version

david.harris@metrostate.edu’s picture

I noticed a typo in that last patch. I don't know if it breaks in all instances, or just mine. When I fixed the typo I was able to use the /node/add/bill#edit-group-path in the 8.x-3.6.

if (hash !== '#' && $(hash, <strong>this</strong>).length) {
  tabFocus = $(hash, <strong>this</strong>).closest('.horizontal-tabs-pane');
} else {
  tabFocus = $this.find('> .horizontal-tabs-pane:first');
}bFocus = $this.find('> .horizontal-tabs-pane:first');
}

the two instances of this should be $this.

This typo is present in 8.x-3.6 and 3.x-dev

geek-merlin’s picture

#7: According to jquery docs that should not matter.
https://api.jquery.com/jQuery/

geek-merlin’s picture

Component: Miscellaneous » Code
Status: Needs review » Reviewed & tested by the community

I can confirm that #6 applies to current version and fixes the issue for me.

anybody’s picture

Version: 8.x-3.x-dev » 4.x-dev
anybody’s picture

Status: Reviewed & tested by the community » Needs work

Conflicts need to be resolved, then we need RTBC again. Please use the MR.

anneke_vde’s picture

StatusFileSize
new2.19 KB

Here is a new version of the patch from #6 for the 4.x version

claudiu.cristea’s picture

Issue tags: +Needs tests

idimopoulos made their first commit to this issue’s fork.

dimilias’s picture

Status: Needs work » Needs review

I have rerolled the patch and added a test for each case.
However, I extended the MR to also include an update to the location hash. I don't see the point of having the ability to work when manually adding the fragment but not being able to see it when clicking the tabs.

Disclaimer though: Feel free to disagree and remove the last commit.

andras_szilagyi’s picture

I confirm the issue is present in 4.x and the code in the MR fixes it.

coaston’s picture

Status: Needs review » Reviewed & tested by the community

Thank You, I can also confirm MR539983 works as expected.

anybody’s picture

Status: Reviewed & tested by the community » Needs work

Still needs tests ad there's an unresolved comment.

coaston’s picture

I see, also I have notice, that my web pages where "field group" is used is slower now. Does anyone experience the same issue after applied this patch?

tvalimaa’s picture

Adding #12 patch will fix my issue to open correct tab by using anchor link.

With this patch:
Link /node/NID/edit#edit-group-workspace will open Workspace tab automatically

Without this patch:
Link /node/NID/edit#edit-group-workspace will open first tab Basic information automatically

anybody’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests

Sorry, tests were added in #15, so this is ready for review!

I can't see reasons for possible performance issues (#19), but should be double-checked!

tvalimaa’s picture

I didn't saw performance difference by adding patch but mainly I was focus my anchor link problem.

benstallings’s picture

Status: Needs review » Needs work

Claude Code says:

Summary

This branch adds the ability to activate a horizontal tab via a URL fragment (e.g. #edit-group-tab2), and updates the URL when users click between tabs. Two files are changed: the horizontal tabs JS and a new test.

---
JS Changes (formatters/tabs/horizontal-tabs.js)

1. Tab priority logic refactored (lines 63-135)

The original code used a single tabFocus variable and only checked the URL fragment as a fallback when no focusID matched. Now there are three variables — defaultTab, defaultTabFromLink, and tabFocus — separating the "saved active tab" from the "fragment-derived tab."

The final resolution at line 135 is:

tabFocus = defaultTabFromLink || defaultTab;

Issue: This inverts the priority. The URL fragment tab now always wins over the focusID (the hidden input that stores which tab was previously active, e.g. after a form submission with validation errors). But defaultTabFromLink is always set — when there's no matching fragment, it falls back to the first pane (line 132). So defaultTab (from focusID) can never be reached. The || defaultTab is dead code.

This means if a user submits a form, gets a validation error on Tab 2, and the page reloads without a fragment, Tab 1 will be shown instead of the tab containing the error. The test testRequiredFieldsActiveTab appears to test this scenario but may be passing because Drupal's separate validation-error-focusing JS (details_validation) opens the error tab after this code runs.

Recommendation: The fragment should take priority only when it actually matches a tab element, and focusID should be the fallback. Something like:

tabFocus = defaultTabFromLink || defaultTab || $this.find('> .horizontal-tabs-pane:first');

where defaultTabFromLink is only set when the hash actually matches (remove the else branch that assigns the first pane to it).

2. var instead of let (line 127)

var hash = window.location.hash.replace(/[=%;,\/]/g, '');

The rest of the file uses let/const. This should be const since hash is never reassigned.

3. history.replaceState on tab click (line 162)

history.replaceState(null, '', '#' + self.details.attr('id'));

Good addition — keeps the URL in sync when users click tabs. One minor note: this uses string concatenation while the href attribute two lines above uses a template literal. Inconsistent but functionally fine.

---
Test (HorizontalTabsActiveTabTest.php)

The test is well-structured with three test methods covering the main scenarios:

- testActiveTabByFragment — navigating with a fragment activates the correct tab
- testRequiredFieldsActiveTab — submitting with an empty required field activates the error tab
- testUrlUpdate — clicking tabs updates the URL fragment

Minor observations:

- Line 1, cspell comment duplicated — cspell:words horizontaltabbutton appears at line 3 and again as cspell:ignore horizontaltabbutton in the class docblock (line 14). Pick one; cspell:ignore in the docblock is sufficient.
- The test setup is thorough and follows existing patterns in the module (cf. HorizontalTabsLabelsTest).

---
Key Concern

The main functional issue is the tab priority logic. As written, defaultTabFromLink always has a value (either the fragment match or the first pane), making defaultTab unreachable. The fragment-based activation works, but it comes at the cost of the focusID mechanism, which is how Drupal preserves active tab state across form rebuilds (e.g. after AJAX or validation errors).

anybody’s picture

Issue tags: +Needs tests

@benstallings maybe prepare a separate MR based on that to test for everyone?

And would be great to have functional tests for this anyway, so we ensure it won't break again.

benstallings’s picture

Assigned: Unassigned » benstallings
benstallings’s picture

@anybody I have made a new branch for that, but currently gitlab is telling me I'm not allowed to push to this project, even though I have push access to the fork. I'll try again later.

benstallings’s picture

Assigned: benstallings » Unassigned
Status: Needs work » Needs review

anybody changed the visibility of the branch 3226844-activate-tab-by to hidden.

anybody’s picture

Issue tags: -Needs tests

Nice work @benstallings and thanks for the test! Code LGTM so if we get another review here, I'm happy to merge this!

anybody’s picture

Status: Needs review » Reviewed & tested by the community

Did the review myself, LGTM. Thanks for the test!!

anybody’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.