Problem/Motivation
Navigation components in Design systems often display differently active links (which link is same as current page). Example: menu, bottom navigation, ...
Example 1: Menu in DaisyUI (https://v5.daisyui.com/components/menu/#menu-with-active-item)
<ul class="menu bg-base-200 w-56">
<li><a>Item 1</a></li>
<li><a class="menu-active">Item 2</a></li>
<li><a>Item 3</a></li>
</ul>Example 2: Dock in DaisyUI (https://v5.daisyui.com/components/dock/#dock)
<div class="dock">
<button>
<svg>...</svg>
<span class="dock-label">Home</span>
</button>
<button class="dock-active">
<svg>...</svg>
<span class="dock-label">Inbox</span>
</button>
<button>
<svg>...</svg>
<span class="dock-label">Settings</span>
</button>
</div>
With menu source it's not possible, as in core block menu (boolean in_active_trail variable), to differentiate active menu links. See
menu.html.twig documentation as reference: https://api.drupal.org/api/drupal/core%21modules%21system%21templates%21...
Proposed resolution
Add a new information to store that in getMenuItems() (MenuSource.php).
So that it will possible to do something like:
{% for item in items %}
{% if item.in_active_trail %}
<div class="dock-active">
{{ item.title }}
</div>
{% else%}
...
{% endif %}
{% endfor %}Issue fork ui_patterns-3508748
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
Comment #2
g4mbiniComment #3
g4mbiniComment #4
g4mbini@just_like_good_vibes I'll be happy to show you my issue with menus !
Comment #7
mortona2k commentedLoaded the menu.active_trail service to use getActiveTrailIds, and then $parameters->setActiveTrail().
Comment #8
grimreaperShould it be done in the menu source or in the links prop type?
Currently the active trail is put as attribute in Links prop type, then I would say you play with that in your templates.
In UI Suite Bootstrap, I kind of follow what core does with either JS for authenticated user or event subscriber for anonymous users (need the companion module in #3493509: [2025-12] blocked implementations and generic stuff)
Comment #9
mortona2k commentedMenuSource is where the links are being loaded by MenuLinkTree->getMenuItems().
That's where I adjusted the parameters being passed in.
This is just like the default system menu block:
https://git.drupalcode.org/project/drupal/-/blob/11.x/core/modules/syste...
I recall finding out that active links are not the same as active menu trail. The active tab/local task is a good example of where .is-active is used. But I think active menu trail classes are generated by the menu tree, and don't need the js for anonymous users.
Comment #10
grimreaperHello,
Stuff like item.in_active_trail is already possible.
When using a pattern with menu source. Active trail is present but not set properly.
Tested the MR and it fixes the issue.
Thanks.
Not merging because main UIP2 maintainers are now @just_like_good_vices and @christian.wiedemann, so maybe needs automated tests.
Comment #11
grimreaperChanging to needs work, Tests in tests/src/Kernel/Source/MenuSourceTest.php should be completed I think.
Comment #12
pdureau commentedComment #13
pdureau commentedComment #14
svendecabooterAs reported in #3526471: [5.0.0-beta2] Menu items do not get is-active class, this MR fixes the issue for me in ui_suite_daisyui for me, after adding some extra logic in the menu component of that theme.
I think having active menu items is pretty basic expected behaviour for a theme, so would be good to get this included sooner rather than later. Having to patch both a module and theme to get a visual indicator of the active menu item, isn't the best situation for getting adoption IMHO. Therefor I took the liberty to increase the priority of this issue. Feel free to lower priority if you disagree.
Comment #15
g4mbiniThis issue as been tested 2 times by @Grimreaper and @svendecabooter and only needs tests now ...
Do you think it could be added to 2.0.6 scope as it blocks some theme implementations ?
Comment #16
just_like_good_vibesHello,
just to add some information about the current implementation, i am questioning here the way it is done,
in comparison to the code in
SystemMenuBlock::buildwe could use
menuTree->getCurrentRouteMenuTreeParameters(,any thoughts?
Comment #17
steffenr@just_like_good_vibes
I run into another issue, with displaying sub menu items of a given parent.
If you use the default UI Patterns menu component (in my case ui_suite_daisyui), you would get all the submenu items and not only the ones related to the parent.
This can be fixed in MenuSource->getMenuItems by using:
$parameters = $this->menuLinkTree->getCurrentRouteMenuTreeParameters($this->menuId);instead of
$parameters = new MenuTreeParameters();Comment #18
just_like_good_vibesHello guys,
i rebased the MR and added some modifications.
still no time to add some tests about that.
so i am asking, what kind of minimal tests do we here to test that feature?
i guess that should be functional tests to have the ability to have the active trail context.
i was tempted to merge, but i put it for review right now, unassigned, someone can take it and review please :)
Comment #19
just_like_good_vibesi want to add also this : if we take care of the active status of links here, then the data has some cache metadata,
to simplify we could say the data would depend on the current url ?
that part was not added in my MR. it brings some complexity right? that part comes at a cost :)
let's discuss this in the next weekly?
Comment #20
rodrigoaguileraTalking about cache I discovered a bug about the menu items being stale because menuId is not initialized yet when `alterComponent()` is called.
I suggest getting rid of the property class menuId and access the configuration every time. What do you think?
Comment #21
rodrigoaguileraI went ahead and made the change fixing a phpstan warning along the way.
Leaving it in Needs review for the removal of the class property but still needs tests
Comment #22
just_like_good_vibesHello,
thank you for the work done.
i think here we need testers, someone wants to take assignments and make some manual tests?
Comment #23
mortona2k commentedComment #24
mortona2k commentedThis issue was recently merged into 2.x. We'll need to review changes and revise the patch.
Comment #26
just_like_good_vibesHello all, and thank you @mortona2k for the updated work.
I opened a new MR instead of pushing over !363, because the approach changes a bit:
(a) the links prop type now carries the active trail information: in_active_trail is declared in the schema, kept only when TRUE;
(b) the MenuSource mimics the recent SystemMenuBlock updates, with the same settings: "Expand all menu links" and "Set the active trail".
Users can now opt in to the active trail when injecting a menu into a links prop, and the items in the active trail can be properly themed in SDC components.
About caching, the route.menu_active_trails cache context is only added when the active trail is used, like core menu blocks do.
Also in the MR, alterComponent() reads the menu ID from the settings (fixes #20)
One difference with core: we keep expanding all menu items by default, so existing ui_patterns configurations keep the same behavior.
Kernel tests added.
Needs review, especially (a) and (b)
Comment #27
pdureau commentedWith the addition of
set_active_trailandexpand_all_items,MenuSourceis becoming a copy ofSystemMenuBlockbut with the data logic decoupled from the rendering. That's cool.However, why not using the
menu.active_trailservice to do the calculation, likeSystemMenuBlockis doing?Comment #28
pdureau commentedmenu.active_trailest présent depuis Drupal 8.0: #2301273: MenuLinkNG part2 (no UI or conversions): MenuLinkTree API and unit testsComment #29
just_like_good_vibesGood point @pdureau :)
We were already using it indirectly: getCurrentRouteMenuTreeParameters() is a thin wrapper around menu.active_trail.
But when marking the trail on a fully expanded tree, it also had one useless database query per render.
So i fixed that with a little refactor (it costs 22 more lines) but saves that query on every render of a marking menu.
Comment #30
pdureau commentedThe goal was to remove lines 😂
My guts tell me than
MenuTreeSourceTrait::buildMenuTreeParameters()is overly complex and doesn't belong here, but that's only my guts. If you are comfortable with the change, go for it.Comment #31
just_like_good_vibesyes we wanted to remove lines when thinking about using the service directly, but having config knobs leads us unfortunately to add some code to cover the different cases...
by the way, listening to the guts is important, vital. i read it again, and yes it is a bit long, but phpmd is happy so complexity seems ok. About its place (e.g. "doesn't belong here"), we are just using the Drupal APIs to process menu tree according to our input knobs. so let's keep it here for the moment, open for future optimizations..
Comment #33
just_like_good_vibesBetter late than never, merged :)
we would like to give a warm thank you to all the people for their valuable inputs and comments.
Team work like we enjoy it.
Now the links prop type and ui_patterns will provide a natural way to deal with active links in menus,
and writing SDC component with active links is now less complex.