Let’s Add Next and Previous Buttons to our Bootstrap Photo Gallery

Update 11/14/2015: This has been converted into a jQuery plugin so the code below may be different from the demo files. For more information on how to use the plugin, read the first section in the previous tutorial.

In our previous tutorial, we learned how to create a photo gallery with Bootstrap. Our gallery looks nice and pretty, regardless of screen size. When an image is clicked, a modal box appears with a larger version of the image. If you haven’t done so, you might want to “Explore Bootstrap’s Grid System” first before getting your hands dirty.
View Demo
View in Github
Now we’re going to add some control buttons right below the large image, so you can navigate through the gallery right in the modal window. Take a look at what we’re building in the image below.
I know that there are plenty of plugins that do this sort of thing. But I like doing things from scratch just to learn how things work. Ready to get started – let’s begin.

Add HTML inside the “Click” Event

We’re going to have to add our markup via Javascript. This is because the contents of our modal box doesn’t really exist yet when the page loads. In our last tutorial, we’re already have a click event where we’re building our large image. We simply need to append to this code. See below (in between where it says “Start of new code” and “End of new code”).

$('li img').on('click',function(){
  var src = $(this).attr('src');
  var img = '';
  //Start of new code
  var index = $(this).parent('li').index();
  var html = '';
  html += img;
  html += '
'; html += ''; html += ''; html += '
'; //End of new code $('#myModal').modal(); $('#myModal').on('shown.bs.modal', function(){ $('#myModal .modal-body').html(html); }) $('#myModal').on('hidden.bs.modal', function(){ $('#myModal .modal-body').html(''); }); });

Explanation: – this click event is inside the small image that was clicked. We just need to know which index it is from the list of images we have. We can achieve this by using jQuery’s .index() method. So we wrote:

var index = $(this).parent('li').index();

Meaning, we want the image that was clicked, traversing to it’s parent (list item) and grabbing it’s index. Then assigning it to a variable “index”. Note that our index is array based – so the first element is a zero.
Next, we create the actual markup that we’re adding right in the modal box. You see we start with our image, then our div containing our next and previous links. You see how we consume the variable “index” that we created previously:

html += '';
html += '';

Notice that our “Next” button has a “+2” for it’s “href” attribute. That’s because we want a number that is ahead of the current image that is showing, plus another because we started with zero – remember? Try out the new code by clicking on an image. As soon as our modal window pops up, you see our new previous and next buttons in place. But don’t click them yet – we haven’t written that part. bootstrap-gallery-2

Create the logic when the buttons are clicked

Now let’s take care of what happens when our buttons are clicked. Let’s think about what we need to achieve for a minute. First, we need to change the image “src” attribute of our large image to the next (or previous) image in the list. We already have our index so that shouldn’t be too hard. We also need to increment (or decrement) our index each time we click. Oh, we also have to hide the next button – once we get to the last image. The same behavior needs to happen to the previous button when we hit the first image. Add the code below right outside our document ready handler:

On a side note, I know developers are always looking for freelance work. I discovered Braintrust: a user-owned talent platform created by and for the world's top talent. Head over to Braintrust and signup today!
 $(document).on('click', 'a.controls', function(){
   //this is where we add our logic
   return false;

This just sets up our click handler for both previous and next buttons. Note that we have “.control” as a class to both links – so we only have to code once. Notice that we’re also binding the click event of our link to a parent element (in this case the document). This binding technique is used because our link is not present yet even when document is ready (reason why we wrote it outside of the .ready()).
Replace the current image
Now let’s add this code inside our click handler:

var index = $(this).attr('href');
var src = $('ul.row li:nth-child('+ index +') img').attr('src');
$('.modal-body img').attr('src', src);

Explanation: – first, we set up a variable called “index” (not the same as the index that we created previously as this is local to the anonymous function it’s in). This variable contains the number that is in the “href” of the link clicked. Variable “src” goes back to our un-ordered list, grabs the “nth-child” with the index as the number, grabs the image inside it and takes the “src” attribute.
Finally, it assigns the “src” value and replaces the current image with it. Increment or Decrement the Link Counters At the same time, whenever our links are clicked, we’d want to change it’s “href” value. Add the code below:

var newPrevIndex = parseInt(index) - 1;
var newNextIndex = parseInt(newPrevIndex) + 2;
    $(this).attr('href', newPrevIndex);
    $('a.next').attr('href', newNextIndex);
    $(this).attr('href', newNextIndex);
    $('a.previous').attr('href', newPrevIndex);

Explanation: – Again, we create 2 new variables: “newPrevIndex” – which as a less than one value of the current index, and “newNextIndex” which has plus two. We then create an “if else” block. We check if the link clicked by checking it’s class, then we change both buttons “href” attributes accordingly.
Hide links when last or first image is reached
Now we need to hide the “next” link when we reach the last image in the list and hide the “previous” when the first image is reached. We also need to re-show them when we go the opposite direction. Add the code below:

var total = $('ul.row li').length + 1;
//hide next button
if(total === newNextIndex){
//hide previous button
if(newPrevIndex === 0){

Explanation: – this part is pretty simple. It simply takes the total number of list items in our gallery (var total), and makes that the basis of our comparisons. You will see the first “if” block checking if the total is the same as the new index. If it is, simply hide the “next” button, if not – show the link again. The next “if” block checks if our previous index is “0” (which is our first item), then hides and shows our “previous” link.
What about if the last item IS clicked? Okay, the above code handles when the links are clicked – but what if the last OR the first item is clicked so the modal window has the first or last item. This will still have BOTH buttons in view right? In this case, we simply need to “trigger” the same click handler we just wrote above. We do this by adding the code below – right when we create the html in our modal window:

$('#myModal').on('shown.bs.modal', function(){
    $('#myModal .modal-body').html(html);
    //this will hide or show the right links:

Some CSS

Finally, adding some styles to our links so it looks better. Note that I didn’t really spend a lot of time styling the links because this is pretty much open to your liking. Instead, I just wrote a couple of lines to make the links presentable:

.next {


So now let’s see what we have: 1) a fully responsive photo gallery (Bootstrap powered), 2) a modal pop up when a thumbnail is clicked and 3) control buttons that navigate through the images once clicked. And we wrote all of this without a plugin! How cool is that! If you haven’t seen the demo, feel free to check it out here.

affiliate link arrowLearnWorlds AI learning


  1. stupid me I couldn’t find it Thanks for the time and effort I like it Is there a mark up you could use to make the modal box full screen?.

  2. Hi great tut I a newbie here and found this tut really helpful thanks I didn’t see the link for this part sorry. Q: is there a way to make the pop up modal full screen? would be good if there was

  3. It seems like this would be great – but I can’t get it to work. I copied the html directly from the demo page and the pop up doesn’t work. Any suggestion?

  4. You want to reset your “figcaptions” before inserting new content.
    something like
    $(‘.modal-body figcaption’).remove();
    $(‘.modal-body img’).attr(‘src’, src).attr(‘alt’, alt).after(figcaption);

  5. hey can you tell me which wordpress plugin will help if i wanna show social like buttons in fancy box (Example: fb like button will be there just next to the prev button)??
    means we can give facebook likes to each and every image in the gallery…
    or implement like buttons on each thumbnail pics…

  6. Hi,
    Great tutorial, but unfortunately I keep getting stuck after pasting the HTML script into my code. The light window shows up fine, but the buttons do not. I tried using the firebug console, but it did not show any errors. Could that script be conflicting with something?

  7. This works great, thank you!
    A problem I’ve encountered is it cannot maintain functionality if you div the ul into rows (to improve the layout when images are of different heights. Any advice on how to either (i) have an orderly layout on a single row or (ii) preserve functionality across rows?

  8. Great post. I really thank that this post was really helpful to my designing of coupon script. Technical post with such clear screenshots and codings are rare and newbies like me will search for post like this.
    thanks Mike keep going with user related contents

  9. hello guys,
    This is not working in IE
    First time cant open properly.
    But next time will open.
    Plz suggestion for issues…
    Thank you

  10. Hi guys!
    First of all, a most splendid guide (yes, I’ve tried quite a few others, few as throughout and explaining as this one)!
    I’ve got two smaller issues though. The first one is related to images with standing images (please pardon me if this is not the correct expression as english is my second language, what I’m after is images where height > width). I would like my modals size to remain the same and the shown images to adjust their size after what’s available. I’ve tried putting “height” and “max-height” with both percentage and pixel-values in various modal-css objects, but they seem to be ignored for some reason. Setting a width in modal-lg (I added modal-lg to the modal-dialog-div for a result of:) works perfectly for setting the width, but a height-setting in the same object is totally ignored.
    Second thought is that it would be lovely if the next-/previous-buttons could react to pressing the keyboard left-/right-buttons, but I unfortunately have very little experience with JS.
    Any hint of how I accomplish either of the above would be very much appreciated!

    • Overriding the height and width of the modal box is a bit quirky. I’ve done it in another project – but messes up with the orientation. So you’ll have to fix that. If it needs to be dynamic – it becomes a problem
      The left / right keyboard click can be achieved by doing something like this:
      if (e.keyCode == 37) { //this is left keyboard button
      $(‘a.previous’).trigger(‘click’) //trigger the left button click
      if (e.keyCode == 39) { //this is right keboard button
      $(a.next).trigger(‘click’) //trigger the right button click
      Something like that. I haven’t tested – so let me know if it works.

  11. Hi…whenever I click on the next or previous button it goes to a page saying this webpage is not found? Any idea. I did alert on the src value which looks correct, but yet it says webpage not found. The javascript console shows the error unable to load local resource? Any clue
    Thanks in advance

  12. Thank you very much for the great plugin, and also for explaining how it works. It really helps me to learn while getting something nice to use in the meantime. I hope to be as good as you some day! ๐Ÿ™‚

  13. Hi, this tutorial is amazing, specially for someone like me, new in bootstrap!!!
    I just have a question.. and what about if i would implemente the modal with a title and just on the bottom a normal link ?

  14. Hi! Great tutorial!
    I am using this as an add on to another bootstrap site I downloaded for a portfolio. Main page clicks on an image to take you to modal1, this photo gallery, click on an image and I have modal2, the individual image, click again, modal2 closes just fine. But then, when I click the X to close modal1 it closes but leaves an overlay on the original page and nothing works, it has to be refreshed. Any idea why? I have spent hours trying to fix this to no avail….Thanks for your help!

  15. Thanks for a great tutorial. Getting into front-end dev now and I learned a lot from it. I’ll be checking out your new plug-in as well. However, I did have a problem with the ‘next’ link showing when clicking on the last image in the gallery first. I added this to the html-building section of code:
    // if clicking on the last image, don’t show the next link
    var len = $(‘ul.row li’).length;
    if (len != (index+1)) {
    html += ‘next »‘;
    The next link will show on any image clicked other than the last one. I tried to use hide(), but that didn’t work. This also solved an issue I had with ‘Type error: undefined’ on the src variable within the controls click function when a thumbnail was first clicked.
    Thanks again!

  16. I checked back and found that my fix above introduced a new bug (clicking the last image first displayed the second-to-last image). So here’s the correct fix for hiding the ‘next’ link when someone clicks the last image first.
    In the controls click function right after the line,
    var index = $(this).attr(‘href’);
    add this:
    // if the last gallery image is clicked first, don’t show ‘next’ link
    var len = $(‘ul.row li’).length;
    if (index > len) {

    • When using
      var len = $(โ€˜ul.row liโ€™).length;
      if (index > len) {
      its working fine but another problem comes here…..after clicking on last link when i click outside and then again click on another link its showing the last link image every time….

  17. Is there a way to just load Thumbnails and only load the larger image if the thumbnail is clicked on? I have a Gallery with lots of images and seems inneficient to load a ton of large images, most of which won’t be viewed until clicked on.

    • Yes, what you do is load the smaller images in the gallery. But add the source to the large images in each of them as a “data-bsp-large-src” attribute. This way, you’re only loading the small images, and only going to the large version on click.

  18. Thanks for a great tutorial!
    I have a small problem with my gallery, if I refresh the page and click on one picture, the next and previous work fine, but if I click on the outside of the pop-up picture to close it and want to pick a new picture, the picture I clicked on the first time will show up. I just donโ€™t know why. Do you have any ideas?

    • I solved the problem, I erased thiw row:
      $(‘#myModal .modal-body’).html(html);
      I do not know why that is helping, I just erased a row one by one and whitout thisone it works.

  19. Hello Michael,
    I’m trying to use your Gallery. I placed it into a md6 column and I display two rows with 3 images on each row. With the previous version (without closing buttons) It worked in a responsive way and also in a smartphone I see two rows with 3 images.
    With the new version (jquery.bsPhotoGallery.js) the images are displayed one per row (so I have 6 rows with 1 images per row).
    Where is the problem ? (I tried to use img class=”img-responsive”) but in that case also on a desktop it shows 6 rows.
    Could you help me, please ?

  20. Hi Michael Soriano,
    Great Article. It is Helped Me.
    Can you please tell me how can i add keyboard events for next and previous button in Popup.
    I mean when i click left arraow previous Image should Appear and when i click right arraow in keyboard next image should appear in popup.

    • It’s definitely something that we can add in the next version. I believe it’s just adding keypress events – with the appropriate key code. Then we bind to the same actions as the links in the HTML. I would have to dig in to see.

  21. Hi Michael,
    thanks for sharing your code and writing the tut, it made adding the code to my site very easy. I have one problem though. Everything works, however, when I click one of the thumbnails the page scrolls to the top before opning up the modal.
    I’ve done a bit of research and my site does have css on the html setting overflow-y: scroll;. If I remove that, the modal works without the page scrolling to the top. The bizarre thing is I also use a bootstrap modal for my cookie policy info on the same site and it works fine.
    The only difference I’ve seen so far is that the cookie policy has a href set to the id of the modal box.
    Have you come across this problem before?

    • Forget the bit about the bizarre thing with the other modal box, I looked at the module and it was (wrongly) including mootools css & js. I edited the code and it also scrolls the main window to the top when a modal opens. Removing the overflow-y:scroll; from the html fixes the problem but I don’t fully understand the implications of removing that css from my template

  22. why can’t i see the buttons after doing all the steps, the Part 1 tutorial works fine, but this one doesn’t work on me

  23. hiii,,,,
    I am using this code,but when i am clicking on last link, next button is still there its not getting hide ,but when clicking on first link its working fine….

  24. Thanks for the great tutorials.
    Just one wish: if we have a REAL BIG gallery, hundred of images or even more, how do we add a pager to gallery?

    • A pager would require a bit more programming. This would done specifically on page load, you limit the images you want to show. The modals and indexes should still work with the limited result set.

  25. Hi Michael, great stuff, but I found a little problem. Using the actual Bootstrap 3.3.7, the three glyphicons (glyphicon-remove-circle, glyphicon-chevron-left, glyphicon-chevron-right) are not there anymore and are substituted by a small box. They have not “been found”. Any idea?

  26. Hi, I followed your tutorial. But I have multiple skips when I reopen the modal several times. The number of photos skipped every time I click the prev/next buttons are the same as the number of times I open the modal.


Leave a Comment.