Add Active Nav Link Class In Pug
Asked Answered
M

3

5

I am having trouble finding a good solution. The problem is I want a dynamically updated active class on my nav items, however I don't know how to do so. Can anyone help me with a solution for giving the nav item corresponding to the current page a certain class, automatically?

This is my layout.pug page:

doctype html
html(lang="en")
    head
        include components/head
    body(id="page-top" role="document")
        include components/header
        main
            block main
        include components/footer

This is what I currently have for my header.pug file:

nav
    img.hamburger-menu(src="img/menu/menu-hamburger.svg" alt="Navigation Menu")
    ul(class="reveal")
      li
        a(href="index.html" ) Home
      li
        a(href="about.html") About
      li
        a(href="services.html") Services
      li
        a(href="contact.html") Contact

Then I have my index.pug and other rendered pages, which start like this:

extends ../layout

block main
  section
    h1 Personally Professional
Mother answered 15/8, 2017 at 18:38 Comment(1)
How do you serve these pages? Are you building the site all at once, or do you have a server running?Kathrinkathrine
F
6

There are a number of ways of going about this. One way is to pass a variable to each page, telling it which page it is.

Let's call this variable name and pass it each page at render-time. You probably have a server (maybe in Node?) rendering these pages, each one for a different route. Well, instead of just instructing it to just render each of those pages, you also pass along a variable giving each route its name (e.g. {name: "index"}). If it is not yet entirely clear to you how you can pass along a variable, have a look at the examples given in the Pug docs.

Now, each page knows its name/type, meaning that we can use this in the lis: at each li, we'll have a look whether it is the one (or, in other words, whether our wanted page name matches that of the list item).

To see whether it is active, we can conditionally add a class to that item. Here an example of how to do it for the index page (this code would augment what's already there in header.pug):

li(class=(name === "index" ? "active" : undefined))
    a(href="index.html") Home
...

(I'm assuming here that you already have an active class in your CSS.)

Fatsoluble answered 15/8, 2017 at 19:38 Comment(3)
Would you please break it down a little more. I'm a little confused what the statement does, which page to put the code you suggested on, as well as where to write in the variable based on my current page structure. Thanks, I'm still fairly new to Pug and JS. I'm trying to write DRY code but sometimes it's tough to learn the ins and outs to do so.Mother
No problem, I fully understand. I've tried to elaborate a bit more, have a look if that clears things up. You'll only need to touch header.pug and your server code. (side-note: how you actually pass that variable to each template depends on your rendering framework, but in most cases it's just in another JS object you pass along with the name of the template when rendering)Fatsoluble
Here is same way of solving this problem, but slightly better with mixing: github.com/pugjs/pug/issues/166 (see the end of thread)Heterogamy
K
1

Here's another way. In layout.pug, I would add the following block:

block nav
  - var active = "index.html"

We use a block here so that pages that extend layout.pug can override the cur variable (and we default to index.html as the active nav link).

Then, in header.pug, you would use the cur variable when setting the classes for each link (see gandreadis's answer for adding the active class to your lis).

Finally, on each of your pages, add the following (we'll use about.pug as an example):

extends ../layout

block nav
  - var cur = "about.html"

//- actual content
Kathrinkathrine answered 16/8, 2017 at 19:48 Comment(0)
I
0

The selected solution works but you might need something more complex, like removing links on pages where they are not needed. So I suggest you go through pug's mixins, which can give things like this:

mixin item(currentType, name, pageSlug, iconSlug)
  li
    if documentType === currentType
      .current
        svg.icon-inline(role='img' focusable='false')
          use(href=iconSlug)
        = name
    else
      a(href=pageSlug)
        svg.icon-inline(role='img' focusable='false')
          use(href=iconSlug)
        = name

Then all you have to do is announce values in a simple list:

.main-nav(aria-label='Main')
  ul
    +item('person', 'Person 1', '/page/person.html', '/sprites/utils.svg#frame')
    +item('place', 'Place 1', '/page/place.html', '/sprites/utils.svg#location')
    +item('article', 'Article 1', '/page/article.html', '/sprites/utils.svg#quill')
    +item('imageGallery', 'Image gallery', '/page/imageGallery.html', '/sprites/utils.svg#picture')
    +item('styleGuide', 'Style Guide', '/page/styleGuide.html', '/sprites/solid.svg#paint-roller')
Issacissachar answered 29/10, 2022 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.