Skip to main content

How to Add Next & Previous Post Navigation Buttons to Blogger

It's pretty abhorrent how Blogger lacks even the most basic functionalities such as navigating between the next and previous posts. For a platform often touted for being suitable for beginners, I'd say you'd have to be an experienced web developer to be able to use it.

Even then, you can't just use it out of the box. You'd have to spend many hours adding code to make it work.

Fear not though, in my Blogger tutorials, I'll show you how you can add custom functionalities to Blogger.

In this post in particular, I'll show you how you can add Next & Previous post navigation to Blogger.

There are many tutorials readily available on the Internet with different implementations. So you might want to shop around a little. I will just show the implementation I have used on this blog.

Note you'll be adding / customizing code, so you need some basic HTML, CSS, and JavaScript knowledge.

Overview

You'll mainly be installing 3 parts:
  • Blogger theme code
  • CSS styling
  • JavaScript
The theme code tells Blogger to fetch the URLs of the next and previous posts and the CSS applies a basic styling.

Once you've done those 2 steps, technically, you have completed the essential parts for adding next and previous post navigation to Blogger.

However, for this implementation, we also want to show a preview of the title of the next and previous posts. The javascript fetches the posts in the background, and then adds the titles to the navigation UI elements.

Blogger Theme Code

Edit HTML

Screenshot of Blogger Theme Menu
Navigate to the Theme menu in Blogger and click the Edit HTML button.

Paste Code - Blogger Theme Code

Screenshot of Jump to Widget Dropdown Menu in Edit HTML UI
In the Jump to widget drop-down list, choose Blog1 or which ever widget your blog post uses.

Screenshot of Blog Widget in Bloger Theme Code
Find the section of
<b:includable id='post' var='post'>...</b:includable>
and click on the triangle to expand it.

Paste the following code before the closing </b:includable> tag:
<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <nav class="nav-growpop">
    <b:if cond='data:olderPageUrl'>
      <a class='prev' expr:href='data:olderPageUrl' expr:id='data:widget.instanceId + &quot;_blog-pager-older-link&quot;'>
        <span class="icon-wrap"><svg class="icon" width="24" height="24" viewBox="0 0 64 64">
          <use xlink:href="#arrow-left-2"/>
        </svg></span>

        <div>
          <h3 class='older-link' expr:href='data:olderPageUrl'/>
        </div>
      </a>
    </b:if>
    <b:if cond='data:newerPageUrl'>
      <a class='next' expr:href='data:newerPageUrl' expr:id='data:widget.instanceId + &quot;_blog-pager-newer-link&quot;'>
        <span class="icon-wrap"><svg class="icon" width="24" height="24" viewBox="0 0 64 64">
          <use xlink:href="#arrow-right-2"/>
        </svg></span>

        <div>
          <h3 class='newer-link' expr:href='data:newerPageUrl'/>
        </div>
      </a>
    </b:if>
  </nav>
</b:if>
This code tells Blogger to check if a previous / next post exist. If so, generate the HTML for the navigation with the URLs linking to the posts.

CSS

Customize Blogger Theme

Screenshot of Theme Menu in Blogger and the Customize Button
In the Theme menu of Blogger, click on the Customize button.

Paste Code - CSS

Screenshot of the Add CSS UI in the Blogger Theme Designer
In the Blogger Theme Designer, click Advanced category, and at the bottom of the list, click on Add CSS. In the text box, paste the following code:
.svg-wrap{
  position:absolute;
  width:0;
  height:0;
  overflow:hidden;
}

.nav-growpop a{
  position:fixed;
  top:50%;
  display:block;
  outline:0;
  text-align:left;
  z-index:1000;
  transform:translateY(-50%)
}

.nav-growpop a.prev{
  left:0
}

.nav-growpop a.next{
  right:0
}

.nav-growpop a svg{
  display:block;
  margin:0 auto;
  padding:0
}

.nav-growpop .icon-wrap{
  position:relative;
  z-index:100;
  display:block;
  padding:13px 5px;
  border:0 solid rgb(240, 113, 113);
  background:rgb(240, 113, 113);
  transition:border-width .3s .15s
}

.nav-growpop svg.icon{
  fill:#fff
}

.nav-growpop div{
  position:absolute;
  top:50%;
  padding:20px;
  width:440px;
  height:144px;
  background:#f8f8f8;
  opacity:0;
  transition:transform .3s,opacity .3s
}

.nav-growpop a.prev div{
  left:0;
  padding:20px 25px 0px 45px;
  transform:translateY(-50%) translateX(-100%) scale(0.75)
}

.nav-growpop a.next div{
  right:0;
  padding:20px 45px 0px 25px;
  transform:translateY(-50%) translateX(100%) scale(0.75)
}

.nav-growpop span{
  display:block;
  padding-bottom:5px;
  border-bottom:1px solid #ddd;
  color:rgb(240, 113, 113);
  text-transform:uppercase;
  letter-spacing:1px;
  font-weight:400;
  font-size:.7em;
  line-height:1.2
}

.nav-growpop > h3{
  margin:0;
  padding:8px 0 10px;
  color:#4d4d4d;
  font-weight:300;
  font-size:1.14em;
  line-height:1.2;
  font-style: italic;
}

.nav-growpop a:hover .icon-wrap{
  border-top-width:40px;
  border-bottom-width:40px;
  transition-delay:0s
}

.nav-growpop a:hover div{
  opacity:1;
  transition-delay:.3s;
  transform:translateY(-50%) translateX(0) scale(1)
}

@media screen and (max-width:520px){
  .nav-growpop a.prev{
    transform-origin:0 50%
  }

  .nav-growpop a.next{
    transform-origin:100% 50%
  }

  .nav-growpop a{
    transform:translateY(-50%) scale(0.6)
  }
}
This code just applies some basic styling so your visitors will see the navigation properly. You can customize it if you have CSS knowledge and don't like what this styling provides.

Once you are done, don't forget to apply the changes by clicking the Apply to Blog button at the top right corner.

JavaScript

By now, you should have a working Next & Previous posts navigation in your blog posts. This last step, we'll add the ability to load content in the background (called AJAX) so we can show the visitor a preview of what the next and previous posts are called.

Edit HTML

Screenshot of Theme Menu in Blogger and the Edit HTML Button
In the Theme menu of Blogger, click the Edit HTML button.

Paste Code - Edit HTML

Screenshot of Edit HTML UI in Blogger with Section of Code Highlighted
In between <script></script> tags in the head section, paste the following code:
        let domCttLded = false;

        document.addEventListener('DOMContentLoaded', function(evt) {
          domCttLded = true;
        });
This code enables us to detect when DOM content is loaded so that we can execute our code only when all DOM elements are loaded. This ensures that we have access to all DOM elements. This also allows us to know for sure that if a DOM element is not found, it's because it doesn't exist on the page, and not because it's still loading.

Save theme when you are done.

Custom Gadget - Helper

Screenshot of Layout Menu in Blogger and the Add Gadget Button
In the Layout menu of Blogger, open an existing HTML gadget or add a new HTML gadget. This gadget will be used to add some helper functions to the blog.
Please make sure you put this gadget as high up in the layout as possible as the helper functions will be required for the rest of the Javascript code to work.

Paste Code - JavaScript Helper

Screenshot of Custom HTML Gadget UI
Make sure the gadget is visible, give it a title, and paste the following code between <script></script> tags in the text box:
If you are putting all the Javascript from this tutorial in the same gadget, make sure this code is on top as the helper functions will be required for the rest of the Javascript code to work.
    const TWL_HPR = {};

    (function() {
      TWL_HPR.ifDomCttLded = function(fct) {
        if (domCttLded) {
          fct();
        } else {
          document.addEventListener('DOMContentLoaded', fct);
        }
      };

      TWL_HPR.getRefererParam = function() {
        return 'refuri='+window.location.hostname;
      };

      const RQSS = [];

     TWL_HPR.getAjaxRsp = function(method, url, param, sendRef, rspType, rqsHdrs, ajaxHldr, disableHdrCt, forceCall) {
          //create unique id from signiture, if an ajax call with same signiture is in process,
        //just return the same ajax call, however, if previously called, but is finished, user can init a new call with same signiture
        //this allows to get update after previous call has ended
        if (!method) {
         return Promise.reject();
        }

          if (sendRef) {
            let p = this.getRefererParam();

            if (param) {
              p = p+'&'+param;
            }

            param = p;
          }

        const RQS = {
         method,
         url,
         param,
         rspType,
         disableHdrCt,
         hasRqsHdrs: false
        };

        const AJAX = new XMLHttpRequest();

        //async, the third parameter, is set to true, async must be true to use responseType
        //setting responseType in synchronous xhr is not allowed
        //further more, there is no point of using promise if not async
        AJAX.open(method, url, true);

        if (rqsHdrs) {
         RQS.hasRqsHdrs = true;
         RQS.rhLen = rqsHdrs.length;

         rqsHdrs.forEach(function(hdrObj) {
          AJAX.setRequestHeader(hdrObj.hdr, hdrObj.value);

          RQS[hdrObj.hdr] = hdrObj.value;
         });
        }

        if (!forceCall) {
         let sameRqs;

         if (RQSS.some(function(r) {
          if (r.method == RQS.method && r.url == RQS.url && r.param == RQS.param && r.rspType == RQS.rspType && r.disableHdrCt == RQS.disableHdrCt && r.hasRqsHdrs == RQS.hasRqsHdrs && r.rhLen == RQS.rhLen) {
           if (rqsHdrs && rqsHdrs.some(function(hdrObj) {
            if (RQS[hdrObj.hdr] != r[hdrObj.hdr]) {
             return true;
            }
           })) {
            return false;
           }

           sameRqs = r;

           return true;
          }
         })) {
          if (ajaxHldr) {
           ajaxHldr.ajax = sameRqs.ajax;
          }

          return sameRqs.p;
         }
        }

        //else if no same rqs or forceCall
        RQS.ajax = AJAX;

        if (ajaxHldr) {
         ajaxHldr.ajax = AJAX;
        }

        //Send the proper header information along with the request
        if (!disableHdrCt) {
         AJAX.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        }

        if (rspType) {
         AJAX.responseType = rspType;
        }

        const P = RQS.p = new Promise((fullfill, reject) => {
         //when loaded
         AJAX.addEventListener('readystatechange', function() {
          if (AJAX.readyState == 4) {
           //the response is return with the original xhr obj
           //you can then read the response and the status and the header info
           fullfill(AJAX);

           const IDX = RQSS.indexOf(RQS);

           RQSS.splice(IDX, 1);
          }
         }, false);
        });

        RQSS.push(RQS);

        AJAX.send(param);

        return P;
       };
    })();
This gives us an TWL_HPR object which houses the helper functions we can then use to easily make AJAX calls and check if DOM content is loaded.

Once done, don't forget to save the gadget.

Custom Gadget - Next & Prev Posts

Now below the helper gadget, we need another gadget for the Next & Previous posts navigation javascript.

We need to make sure the helper gadget loads first, so make sure the Next & Prev posts gadget is below the helper gadget.

You can use an existing HTML gadget or create a new one. The reason we separate the code into 2 gadgets is because we can edit the code separately and making maintenance and management easier.

Screenshot of Custom HTML Gadget UI
As usual, make sure the gadget is visible, give it a sensible title so you can identify it in the future, and paste the following code between <script></scirpt> tags in the text box:
TWL_HPR.ifDomCttLded(function() {
      const NAV = document.querySelector('.nav-growpop');

      if (NAV) {
        const NEXT = document.querySelector("h3.newer-link"),
              PREV = document.querySelector("h3.older-link"),
              CSS = '.post-title-container .post-title',
              W = 64,
              H = 64,
              VB = '0 0 64 64';

        //create svg
        const WPR = document.createElement('div');

        WPR.classList.add('svg-wrap');

        const SVG_1 = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
              SVG_2 = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

        //property doesn't work on svg element
        SVG_1.setAttribute('width', W);
        SVG_2.setAttribute('width', W);

        SVG_1.setAttribute('height', H);
        SVG_2.setAttribute('height', H);

        SVG_1.setAttribute('viewBox', VB);
        SVG_2.setAttribute('viewBox', VB);

        const PATH_1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'),
              PATH_2 = document.createElementNS('http://www.w3.org/2000/svg', 'path');

        PATH_1.id = 'arrow-left-2';
        //path1.d doesn't work
        PATH_1.setAttribute('d', 'M26.667 10.667q1.104 0 1.885 0.781t0.781 1.885q0 1.125-0.792 1.896l-14.104 14.104h41.563q1.104 0 1.885 0.781t0.781 1.885-0.781 1.885-1.885 0.781h-41.563l14.104 14.104q0.792 0.771 0.792 1.896 0 1.104-0.781 1.885t-1.885 0.781q-1.125 0-1.896-0.771l-18.667-18.667q-0.771-0.813-0.771-1.896t0.771-1.896l18.667-18.667q0.792-0.771 1.896-0.771z');

        PATH_2.id = 'arrow-right-2';
        PATH_2.setAttribute('d', 'M37.333 10.667q1.125 0 1.896 0.771l18.667 18.667q0.771 0.771 0.771 1.896t-0.771 1.896l-18.667 18.667q-0.771 0.771-1.896 0.771-1.146 0-1.906-0.76t-0.76-1.906q0-1.125 0.771-1.896l14.125-14.104h-41.563q-1.104 0-1.885-0.781t-0.781-1.885 0.781-1.885 1.885-0.781h41.563l-14.125-14.104q-0.771-0.771-0.771-1.896 0-1.146 0.76-1.906t1.906-0.76z');

        SVG_1.append(PATH_1);
        SVG_2.append(PATH_2);

        WPR.append(SVG_1, SVG_2);

        NAV.parentNode.insertBefore(WPR, NAV);
        //end svg

        //generate next / prev article titles
        function genTtl(item, name) {
          if (item) {
            TWL_HPR.getAjaxRsp('GET', item.getAttribute('href'), undefined, undefined, 'document').then(function(xhr) {
              if (xhr.status == 200) {
                const NAME = document.createElement('span'),
                      TTL = document.createElement('h3');

                NAME.textContent = name;
                TTL.textContent = xhr.responseXML.querySelector(CSS).textContent;

                item.append(NAME, TTL);
              }
            });
          }
        }

        genTtl(NEXT, 'Next Story');
        genTtl(PREV, 'Previous Story');
      }
    });
This code creates the SVG elements for the arrow icons of the navigation. Then, it performs the AJAX call for the next post and the previous post respectively.

Once an AJAX call is completed, it retrieves the post title using the defined css selector and adds it to the navigation as a preview.

Here, the css selector is defined in a constant CSS as '.post-title-container .post-title'. Depend on your theme, you may have a different css selector for your post title, so you might have to change this.

When you are done, make sure you save the gadget.

End

I know this post has been super long, and the code is super lengthy. But hopefully, you got everything right. If so, you should be able to see the same Next & Previous post navigation as on my blog posts:
Screenshot of Example of Next and Prev Post Navigation on My Blog Posts

Comments

  1. hi
    i have a problem
    There is no share, icon, or title
    The extension only works in moving between topics, but nothing appears empty box but it works

    ReplyDelete
    Replies
    1. "There is no share, icon, or title"
      - Not sure what you mean by that. This tutorial only adds next and previous buttons.

      "The extension only works in moving between topics, but nothing appears empty box but it works"
      - Do you see the arrows in the buttons?
      - Do you see the names "NEXT STORY", "PREVIOUS STORY"?

      Delete
    2. - Do you see the arrows in the buttons?
      - Do you see the names "NEXT STORY", "PREVIOUS STORY"?
      yes that what i mean i did't see arrows in buttons or next story just empty but the button is working

      Delete
    3. Sounds like the Javascript isn't working.

      If you can right click on the button and "Inspect element", you would able to diagnose the problem more.

      You should be able to see that the button HTML tag is wrapped around by this tag:
      <nav class="nav-growpop">

      Then right before this tag, there should be this tag:
      <div class="svg-wrap">

      Hmmm, wish I can post screenshots in Blogger comments...

      Delete
  2. This post not educating. Most people who use your codes are not working in "notable" template, thanks.

    ReplyDelete
    Replies
    1. Yes, "Notable" is the theme template I'm using. It works for me. Sorry to hear you can't get it to work.

      I know the post can be confusing, I wish I could explain it better.

      Delete
  3. on my site www.primetv9ja.com, I have the navigation already but post title and Next story isnt showing
    Whats the problem??

    ReplyDelete
    Replies
    1. Looks like you didn't do these 2 parts correctly: "Custom Gadget - Helper" and
      "Paste Code - JavaScript Helper", as the TWL_HPR object is undefined.

      Delete
  4. Arrow sign is not there.
    My trial website
    https://vzbzjs.blogspot.com

    ReplyDelete
  5. Thank you for making this post. I'm not very experienced with changing HTML and CSS, but with your instructions and code I now have navigation tabs on each post.

    However, similar to the first commenter, the tabs are functional for navigation, I can see the coral colored button, and when I hover over it, it expands to show a whitish box, however the box is empty (i.e. no title, no next story). On Safari it's just a coral box, on Chrome, there is a white arrow in the box, but still no words.

    In the article you say: "Here, the css selector is defined in a constant CSS as '.post-title-container .post-title'. Depend on your theme, you may have a different css selector for your post title, so you might have to change this." I am using Soho Theme on Blogger. How do I find the css selector for my post title. Hoping the problem is as simple as correcting this part. But if not, I am happy to at least have the navigation buttons. Thanks in advance for your help.

    ReplyDelete
    Replies
    1. In chrome, you can right click on your post title, and select "inspect" or "inspect element".

      It will show you the html. For example, mine looks like this:
      <div class="post-title-container">
      <a name="135720982752019292"></a>
      <h3 class="post-title entry-title">

      That is how I derived the css selector. The first div has a class 'post-title-container'. Inside it, there is a h3 with the class 'post-title'.

      So the selector '.post-title-container .post-title' selects the h3 element.

      The dot means 'class', and the space in between means '.post-title' must be inside '.post-title-container'.

      So the complete meaning is look for an element with class 'post-title' that is inside an element with class 'post-title-container'.

      Hope this helps.

      Delete
    2. Ah, brilliant! That was it!.... Mine was slightly different ("div.post"). I deleted "-title-container" and that fixed the problem. Now the Next/Previous tabs and post title show up properly. So glad you mentioned that possible hiccup in your post. Thanks so much!

      Delete
  6. Hello, thanks a lot for all these information. I tried to do everything you wrote but It doesn't function. I see no arrow, nothing. I tried to put the Gadget html/JavaScript in the sidebar of the body page and then in the sidebar from the item page. No difference.
    As I didn't really understand what you mean by your last point, I followed your instructions in the comments. My title shows
    div class="post-title-container"
    a name="988939668543577009" /a
    h3 class="post-title entry-title"TITEL OF MY PAGE h3
    (I had to take away the arrows as it looks like they are not permited)
    I have really no idea what I did wrong and what I can do as I tried this several times for the same result.
    My page is sy-olena.ch Thanks a lot if you can help me.

    ReplyDelete
    Replies
    1. Hi Sailing,

      I had a look at your website, and I don't see the html for the next and previous page buttons.

      I also noticed that your html structure is different than mine. This means the code I provided may not work for you. Or it could be that you did it wrong.

      In my post there is a section about editing html of the blogger theme code. Make sure you did that part correctly.

      Delete

Post a Comment

cusG_relatedPost_html

Popular posts from this blog

Japanizing

Street Fighter: Chun-Li Outtakes - Lilan Bowden