Menu shortcuts don't show as active on current page

Hello,

I have a Neos.Neos:Menu node type for my main navigation in the site. Since some nodes are elsewhere in my nodeTree, I have to use a few Neos.Neos:Shortcut nodes to show the target page on the Menu.

If I’m not mistaken, that’s the way to go with the Menu logic. However, there is an inconvenience here: the shortcut link on the menu (actually, the <li> element) doesn’t adopt the class ‘current’ when I am viewing the Shortcut’s target page.

So, how do you solve this problem ? I’d guess this is a common problem, so I’d also guess that there is a common solution to it :slight_smile:

Thanks in advance !

Hi :slight_smile:

Can you show us how you configured your menu (your Fusion code)? And how you expect the current state to be transferred to your Fluid template,

Cheers,

Soren

Hi Soren,

Well, my setup is pretty much default and now that I took a look at my clean neos demo package installation, I see the problem there as well.

While viewing the “Features” page, which is an actual node:


You can see the “current” class in the inspector, which makes the link blue

However, while viewing the “Home” page, which is a shortcut to the Site root:


You can see the list element is using the “normal” class.

(Ignore the highlighted Try me block, I just had my mouse there while screenshooting).

My setup in my project is just a customized version of the demo site’s Menu:

Fusion:

mainMenu = Menu {
    attributes.class = 'header-menu'
    startingPoint = ${q(site).find('[instanceof Neos.Neos:Document][uriPathSegment="members-area"]').get(0)}
    startingPoint.@if.cond1 = ${Security.hasRole('Vendor.Site.Member:User')}
}

Fluid:

{mainMenu -> f:format.raw()}

I guess the way to solve this would be to create a class that extends Neos\Neos\Fusion\MenuImplementation and override the @class attribute in fusion and then override the function that builds the list.

Now, before I dive into this solution, has anyone already made a fix for this ?

Hi, I’m using a custom “Navigation.ItemRenderer” and check if the active document is the same as linked in the shortcut using this:

String.indexOf(q(node).property('target'), documentNode.identifier) > -1

Sounds interesting. Sorry I’m not familiar with what you’re describing, could you give me some more info ? For example, where do you define that your custom Navigation.ItemRenderer will be used ?

Let’s say you want to render the navigation in your page template (could be anywhere) like this:

{navigation -> f:format.raw()}

Then you would have to define that in the page fusion. In my case it looks like this:

navigation = Your.Site:Component.Navigation {
    startingPoint = ${site}
}

Passing the site as the starting point gets all items below the root/home page. You can use a flowquery to pass any other page as the root for the navigation. When using shortcuts this usually makes sense, for example if you identify that root page node or root shortcut node (which contains your menu shortcuts) via uri path segment, this flowquery could be used:

startingPoint = ${q(site).find('[instanceof Neos.Neos:Document][uriPathSegment = navigation]').get(0)}

The fusion of the navigation component could look like this:

prototype(Your.Site:Component.Navigation) < prototype(Neos.Fusion:Component) {
    @context.node = ${this.startingPoint}

    navigationItems = Neos.Fusion:Collection {
        collection = ${q(node).children('[instanceof Neos.Neos:Document][_hidden != TRUE][_hiddenInIndex != TRUE][hideFromMainMenu != TRUE]')}
        @if.notEmpty = ${this.collection.count() > 0}
        itemName = 'node'
        itemRenderer = Your.Site:Component.NavigationItem
    }

    renderer = afx`
      <nav class="site-navigation">
          <ul>
              {props.navigationItems}
          </ul>
      </nav>
    `
}

And the fusion of the navigation item component (what i called Navigation.ItemRenderer earlier):

prototype(Your.Site:Component.NavigationItem) < prototype(Neos.Fusion:Component) {
    node = ${node}
    
    itemClass = Neos.Fusion:RawArray {
        base = 'site-navigation__item'
        current = 'site-navigation__item--state-current'
        current.@if.isCurrent = ${node == documentNode || String.indexOf(q(node).property('target'), documentNode.identifier) > -1}
    }

    renderer = afx`
        <li class={props.itemClass}>
            ...
        </li>
    `
}

Here in itemClass you see the condition which checks if the item is active/current. It sets the class site-navigation__item--state-current if the condition is true (its the current page node OR its the shortcut pointing to the current page).

Hope this helps, it’s a simplified example to illustrate the used pattern.

Check for example https://github.com/code-q-web-factory/Neos-Skeleton to find a more complete implementation of this pattern (excluding the adjustment for checking if shortcut is active), also including multi-level menus.

Thanks a lot for the detailed explanation Jan, that’s definitely an easier way to do it than the one I had in mind hehe.