How to make buttons remain 'active' after they're clicked?

13,366

Solution 1

You need to identify the page you are currently on.

var page = window.location.href;
page = page.substr((page.lastIndexOf('/') + 1));
page = page.split('.');
page = page[0];
//At this point you will have the current page only with no extension or query paramaters
//I.E. "About Us"
page = page.toUpperCase();
//This accounts for upper or lower casing of urls by browsers.
switch(page) {
    case "ABOUT US":
        $('#About').addClass('< name of active button class >');
        break;
    case "SERVICES":
        $('#Services').addClass('< name of active button class >');
        break;
    case "CONTACT US":
        $('#Contact').addClass('< name of active button class >');
        break;
}

If you're not using jQuery replace this line:

$('#< element name >').addClass('< name of active button class >');

with this line:

document.getElementById("< element name >").className += " < name of active button class >";

Hope this helps.

Solution 2

Best just to stick to using CSS classes with some JS. This way you can mix both styles for the pseudoclass (:hover) as well as the CSS class.

$('.myButtonLink').click(function() {
  $(this).addClass('active_class');
});

Or if you want to toggle it.

$('.myButtonLink').click(function() {
  $(this).toggleClass('active_class');
});

This way if there any changes in your layout, you only have to update the CSS styles that are apart of that class and not have to update your JavaScript code.

You can use the window or localStorage element to keep stage across page refreshes.

var key = getStorageKeyFromLink(link);
window.activeStateLookup = window.activeStateLookup || {};
window.activeStateLookup[key] = {
  element : link
};

Now when your page loads you can just update all the images:

window.onload = function() {
  var lookup = window.activeStateLookup || {};
  for(var key in lookup) {
    var element = lookup[key].element;
    element.addClass('active_class');
  }
}

--- EDIT ---

Here's your DEMO.

The example uses localStorage, but it would work the same with the window object. Be sure to copy and paste the code and try it out on your local machine since jsfiddle has some blocks against what's going on.

http://jsfiddle.net/GDXLb/7/

Solution 3

You could use a little jquery to see what the url is, parse it and then re-apply the active class to the appropriate link.

I.E ( i haven't tested this... it's more of an idea...)

var path = window.location.pathname;

$(a).each(function(){
    if (path.indexOf($(this).prop("href")) > 0){
        $(this).child("button").addClass("active");
        break;
    }
});
Share:
13,366
OCD
Author by

OCD

Updated on July 26, 2022

Comments

  • OCD
    OCD almost 2 years

    I'm currently using the following code for my menu items:

    HTML

    <li>
    <a id="About" class="button" href="About Us.cshtml">About Us</a>
    </li>
    <li style="margin-left: 30px;">
    <a id="Services" class="button" href="Services.cshtml">Services</a>
    </li>
    <li style="margin-left: 30px;">
    <a id="Contact" class="button" href="Contact Us.cshtml">Contact Us</a>
    </li>
    

    CSS

    #About {background-image: url(../Buttons/About.png); width: 87px;}
    #Services {background-image: url(../Buttons/Services.png); width: 112px;}
    #Contact {background-image: url(../Buttons/Contact.png); width: 117px;}
    a.button {height: 20px; display: inline-block; background-repeat: no-repeat}
    a.button:hover {background-position: 0 -20px;}
    a.button:active {background-position: 0 -40px;}
    

    I need to get the buttons to remain in the 'active' state after they're clicked and the page loads/refreshes etc.

    If the solution requires javascript, please bear in mind that I'm a rank amateur so I'll need any explanations in layman's terms (preferably with examples).

    • xiaoyi
      xiaoyi over 11 years
      I don't think this question deserve -1.
    • bozdoz
      bozdoz over 11 years
      You want it to remain active until the page loads, or even after the page loads? The latter requires you to get the URL with javascript (not impossible).
    • Ryan B
      Ryan B over 11 years
      The common approach is to apply an additional class to the link that mimics the :hover, are you using PHP or anything?
    • Wesley Murch
      Wesley Murch over 11 years
      I don't think this question deserves +7 either... but hey, why not?
    • Darren Wainwright
      Darren Wainwright over 11 years
      I think the -1 might have come because more or less the same question was asked by Leon 45 mins before stackoverflow.com/questions/13648674/…
    • Wesley Murch
      Wesley Murch over 11 years
      Am I correct that you are looking for something like :visited? See also: hacks.mozilla.org/2010/03/…
    • Darren Wainwright
      Darren Wainwright over 11 years
      @WesleyMurch - visited would end up having the style applied to all clicked-links. Eventually, after navigating through, all links would end up the same color.
    • Matheus Azevedo
      Matheus Azevedo over 11 years
      I think that the only reliable approach is to use server-side scripting or cookies.
    • Wesley Murch
      Wesley Murch over 11 years
      @Darren: Solved by specificSelector:visited, in this case there are hrefs and ids to use, but I realize that's not a solution anyhow... but I don't get it - each link should permanently change once clicked?
    • Darren Wainwright
      Darren Wainwright over 11 years
      @WesleyMurch. That's what visited does..it's to give the user a visual clue of links they have already visited before. Ever noticed that when you search Google some links might be purple; you have already visited those ones before. Also AFAIK, you can only apply :visited to links, and not buttons, and have it work as expected.
    • OCD
      OCD over 11 years
      @ bozdoz - After the page loads.
    • OCD
      OCD over 11 years
      @Ryan B - I'm not entirely sure what you mean by adding an additional class to mimic :hover. I'm not currently using anything other than straight-up html & css. I'd rather keep it that way but I'm prepared to get some JS involved...not that I know JS too well.
    • OCD
      OCD over 11 years
      @ Darren - Actually, that question was relating to getting the mouseover and active states working while using a combination of IDs and classes. I mentioned in that thread that I would then be looking to keep the buttons in the active state after they're clicked and this would likely require JS so I'd ask the JS question on a separate thread - since it's a separate question.
    • OCD
      OCD over 11 years
      @ Wesley Murch & Darren - No, they should not be permanently active once clicked - only while the user is on that page. I've seen various examples of JS knocking about that somehow sets the relevant class on the clicked item and also removes that same class from other items...so clicking on 'About' would result in that button becoming (and remaining) active, but then clicking on 'Services' would remove the active attribute from the 'About' button and add it to the 'Services' button etc.
    • Darren Wainwright
      Darren Wainwright over 11 years
      @LeonLawrence - I understand that, I was letting Wesley know why visited is not the correct solution. I put an answer on here about an hour ago with an idea. It might help you.
  • xiaoyi
    xiaoyi over 11 years
    I need to get the buttons to remain in the 'active' state after they're clicked and the page loads/refreshes etc. why this is correct?
  • War10ck
    War10ck over 11 years
    @Garry If the page refreshes, you'll lose the class you just added.
  • xiaoyi
    xiaoyi over 11 years
    I need to get the buttons to remain in the 'active' state after they're clicked and the page loads/refreshes etc. why this is correct?
  • War10ck
    War10ck over 11 years
    @matsko Does this not have the same problem as Garry's example. Once the page reloads, the DOM is cleared meaning the class you just added becomes lost and irrelevant. Classes don't stay from page to page.
  • matsko
    matsko over 11 years
    Just use localStorage to maintain the state then. Or use the window element.
  • Matheus Azevedo
    Matheus Azevedo over 11 years
    This way, only the page he's viewing will have the 'active' class. I think he wants to keep all visited pages 'active'
  • War10ck
    War10ck over 11 years
    @MatheusAzevedo That needs to be clarified. It doesn't make sense to make every button that you ever pressed active. That would be considered visited. If I'm on "contact us" and I came from "about us", "contact us" is active while "about us" was visited. If that is indeed what is desired though, then just use the :visited CSS styling of <a> tags.
  • OCD
    OCD over 11 years
    Actually, if this solution results in only the current page being 'active' then that's exactly what I'm looking for. I'm no JS expert though...where exactly would I need to insert the above code? Additionally, what is "< element name >" referring to? should I be replacing this with something?
  • OCD
    OCD over 11 years
    Might seem like a silly question but am I supposed to paste the above into a .js file and reference it in the <head> of my webpages? Either way, Webmatrix is flagging up: "Can't have 'break' outside of loop". The buttons don't remain active either. I appreciate the help though. I'm lost otherwise - could you clarify? Thanks.
  • Darren Wainwright
    Darren Wainwright over 11 years
    As mentioned, not tested, just an example. Though remove the break and try. the each is actually performing a loop - it's jquery. You would typically put javascript in the head of your page. For this one to work you would also need to reference the jquery script. go to jquery.com for the library and installation help.
  • Darren Wainwright
    Darren Wainwright over 11 years
    Some others have said server-side is also an option. I guess for us to help you more you need to say what languages you are capable in.
  • War10ck
    War10ck over 11 years
    @LeonLawrence The element name would be the id property of the button. (I.E. "About", "Services", or "Contact"). As far as the class goes, you place the name of the CSS class you created. The above code would need to be placed in a section that runs on document ready. $(document).ready(function () { _Place Code Here_ } });. My apologies, I should have asked too. Are you using the jQuery framework or just plain javascript?
  • War10ck
    War10ck over 11 years
    @LeonLawrence If you not using jQuery you can still determine when the document is ready and apply this coding by applying a listener as follows: `document.addEventListener( "DOMContentLoaded", function(){ document.removeEventListener( "DOMContentLoaded", arguments.callee, false ); < Add above code here > }, false );
  • OCD
    OCD over 11 years
    I'm not currently using jQuery or any other framework. So I guess it's just javascript. The whole site is just CSS and HTML until now. Pathetic as it may sound, those are the only languages/utilities I'm even loosely familiar with. To be honest, javascript is largely gobbledigook to me. Darren has suggested I install jQuery. I'm happy to try this if it'll help. p.s. I have no idea what 'document ready' is/means.
  • OCD
    OCD over 11 years
    @ War10ck - ok, I'll try applying the listener & come back to you.
  • OCD
    OCD over 11 years
    Vaguely capable in html & css. That's about it... :-/
  • Darren Wainwright
    Darren Wainwright over 11 years
    Yep, you're going to need to learn some javascript to do this on the browser end. Highly recommend using jquery as it encapsulates a LOT of what you need to do, and can be done with simple calls.
  • War10ck
    War10ck over 11 years
    @LeonLawrence You are all good man. That's not pathetic at all. You got to start somewhere. JavaScript can be a bit tricky as its got some work arounds that have to be made to get some things to work correctly. And I'm sure you'll find sometimes things never look the same in different browsers. Ah the joys of web dev. All good though man. My apologies for being a little vague on 'document ready'. The DOM is the document object model (basically a tree of all your html elements on the page). You can view this link for more clarity. DOM.
  • War10ck
    War10ck over 11 years
    @LeonLawrence When a document is "ready", it means the browser has parsed all the HTML code and rendered it on the page in the DOM itself (in other words, your code has been successfully applied to the page). You have to wait for this to occur as you're applying JavaScript to an element on the page. If the JavaScript ran before the element was loaded, the browser would have nothing to add the class to and the button would be rendered as normal without the additional 'active' styling that you're applying.
  • OCD
    OCD over 11 years
    @ matsko - 1. I do not require 'toggle' functionality. Therefore, do I need to implement the 1st, 3rd and 4th blocks of code you have provided?. 2. Am I to assume that I should replace '.myButtonLink' with '.button' since this is class I am using? or should I replace with the id e.g. 'About'? 3. Should I be replacing 'active_class' with '.button:active'? - please clarify. 4. Do I need to encapsulate each of these 3 blocks of code in <script> tags? where should I insert them? can I simply include all 3 in the same <script> tag?
  • matsko
    matsko over 11 years
    My post is a bit patched up because I changed and added things so quickly. Take a look at the demo that I posted. Basically you can just put the JavaScript code into it's own file and include that with a script tag as well as script tag for jquery right before. Then include the CSS contents into it's own file and link it to the page using the <link> element.
  • OCD
    OCD over 11 years
    @ matsko - So I realised that it wasn't me being completely stupid. I'm referencing jQuery properly and calling your code just fine. The thing is, if I replace the urls that the buttons are pointing to with '#', the buttons do indeed retain the active state - it just doesn't work once the page loads after clicking (when the buttons are pointing to their respective pages, of course). Any idea how to remedy this? Or will it turn out that server-side code really is the only way forward (as has been suggested)?
  • OCD
    OCD over 11 years
    @ War10ck - I worked out where I was going wrong and eventually managed to get jQuery involved. Following that, your suggestion was the only one that worked - and it works well. So props to you and thanks for your help and for taking the time to explain. Massively appreciated!
  • War10ck
    War10ck over 11 years
    @LeonLawrence Never a problem man. Always glad to assist. Good luck and happy coding!