Expand/Hide accordion feature explained

July 4th, 2009 by Tobias Leave a reply »

During the last weeks several people have asked me about the Expand/Hide functionality on the WP-Table Reloaded plugin page and the documentation page:

Example

Example Content of Example Section

Some people asked whether it is a WordPress plugin or if I could explain how it works. That’s why I decided to write this article, so all of you can benefit from it.

The mentioned plugin and documentation pages have a lot of information on them that is divided into several sections or paragraphs as they deal with different aspects of the plugin. For readers who come to one of these pages, this information might at first be too much as they probably are not interested in all of it and just want a certain piece of information. So, why bother them with stuff they don’t want?
As I’m currently getting into the nice JavaScript framework jQuery a little bit, this seemed perfect for it. Additionally I had read the nice articles about Accordion Madness on learningjquery.com which nicely explain the usage of the functions.

So I adapted some of that code to fit my needs, with one addition: I wanted a “fall-back” for people with browsers where JavaScript is not enabled. For them the functionality should just be hidden, including the “hide” or “expand” links which wouldn’t work for them anyway. This means that I’d have to add those by the JavaScript code, and I’d also have to hide the contents with it. That way people without JavaScript will just see the complete page with all content (and possibly the stuff they don’t need).

Ok, now let me get to some code, to show you how it works and to give you an idea on how to implement it on your site, if you want.
As I said, the content of the pages is divided into sections (like “Download”, “Features”, “Screenshots”, “Demo” and so on). To group them, we’ll just enclose the content in a HTML <div> tag while the section heading will go into a <h3> tag. (It doesn’t necessarily have to be a <h3> tag, but that’s probably the most fitting on most blogs, as the <h1> and <h2> tags are probably already used for the blog and post titles.)
The result looks like this (with some arbitrary content):

<h3>Heading 1</h3>
<div class="slide">
Content of Section 1
</div>
<h3>Heading 2</h3>
<div class="slide">
Content of Section 2
</div>

Note that the <div> tags also got the CSS class “slide”. I’ll be using that as a jQuery selector later. And of course you can add as many of those sections as you want, as long as they have this structure.

Additionally to the HTML code we need to load the jQuery library and our custom JavaScript into the page. I recommend to put all code (which I’ll be showing) into a script called “page.js” which is stored in the theme folder of your WordPress. To load the files, put the following lines at the end of your page:

<script type='text/javascript' src='/wp-includes/js/jquery/jquery.js?ver=1.3.2'></script>
<script type='text/javascript' src='/wp-content/themes/YOUR-THEME/page.js'></script>

Note: This is actually not the best way to load jQuery on a WordPress powered site, as e.g. a plugin might have already loaded it. So make sure this is not the case and eventually remove that line from the code above. Also, the path to the page.js needs to be changed to the correct location on your server.

Ok, let me sum up to this point: Nothing has really happened yet to users with JavaScript enabled. Nothing is “expanding” or “hiding” so far, there are not even “hide” or “expand” links, but we have laid the foundation for our JavaScript code.
This JavaScript code will add those links, hide the content that shall initially be hidden and add the actual toggle functionality.
So, here it is, the content of the page.js:

jQuery(document).ready(function($){
 
    var expandhide_text = '<span class="expand">expand</span><span class="hide">hide</span>';
    $('.slide').hide().prev().append(expandhide_text).addClass('slidehidden');
 
    $('h3').click(function() {
        $(this).toggleClass('slidevisible').toggleClass('slidehidden').next().toggle();
        return false;
    });
 
});

Expected more? Well, sorry to disappoint you :-)

Ok, this is not yet quite it. We have one more thing to do, but that’s CSS.
But let me first explain what the above code does.
Everything is enclosed in a jQuery(document).ready(); function block. This is a very important jQuery command, basically meaning that the enclosed code will be run as soon as the frame of the page is loaded and everything we need is available. Note that I used the complete jQuery() function instead the shortcut $(). This is to prevent errors if a second JavaScript library, like Prototype, is loaded.

The first two lines in the code then add the “expand” and “hide” links to the heading (defined as HTML in the variable expandhide_text). This HTML is appended to every <h3> tag infront of a <div> tag with the “slide” class – but only after hiding those (as they shall be hidden initially). Now, one might want that a section is not initially hidden, but still has the Hide/Expand feature. You can see that for the “Download” section on the plugin page of WP-Table Reloaded for example. But to keep things simple for now, I’ll not include how to achieve this in this post but maybe in a later one.

The next lines actually contain the magic: It tells all <h3> headings what to do, if someone clicks on them: Toggle two CSS classes (which we’ll need later) and then toggle the next DOM element (which is the <div> with the content we want to show or hide).

So, we’ve come pretty far now: If the user has JavaScript enabled, all content in a “slide”-<div> will be hidden and can be toggled when clicking on the <h3> heading above it. For this he well see an “expand” and a “hide” link next to the heading.
Well, and that’s some sort of problem: Right now, the user will see both of those links, which doesn’t make sense. And that’s where the CSS and the two mentioned CSS classes kick in. We could also have done this with JavaScript, but, hey, why not use the methods already available?!

We just need to add the following lines to the CSS (probably the file “style.css” in your theme folder):

h3 {padding-top:10px; border-top:dashed gray 1px; cursor:pointer;}
h3 span {display:none;position: absolute; right: 10px; font-size: 12px; color: gray;}
h3.slidehidden .expand {display:inline;}
h3.slidehidden .hide {display:none;}
h3.slidevisible .expand {display:none;}
h3.slidevisible .hide {display:inline;}

This code will format our <h3> headings and the “expand”/”hide” links a little bit (I just copied this from my page. It’s possible that this won’t really look good in other theme, that’s why you’ll probably have to experiment a little bit with the colors and borders.)
The first line adds a dashed border to the <h3>, to visually separate the sections a little bit. It also sets the cursor to “pointer” (usually that’s the “hand” that you see when hovering over a link). We need to do this, because we actually don’t use real <a>-links but we want to give the user the feeling we did :-)
The second line hides all <span>s that are contained in a <h3> heading. More importantly it also positions them: On my page I wanted them to be aligned to the right of the heading, be a little bit smaller and a different color.
And finally the remaining lines tell the <span>s (or better the “expand” and “hide” links) when to be visible and when to be hidden: The “hide” link shall be visible when the content is visible, and it shall be hidden, when the content is hidden. The same applies for the “expand” link, just vice versa.

And that’s basically it.
To sum up:
We created some HTML markup (<h3> headings and <div>s) for the content sections and their headings. They got some CSS classes for easier selection in CSS and JavaScript.
Then we added some JavaScript using the jQuery library. This will add the “expand”/”hide” links (Remember that we don’t need those, if JavaScript is disabled, which is the reason why we use JavaScript to add them to the page.) And it will give the <h3> headings (and the <span>s within it) their behaviour: When clicked, the content <div>s below them will be shown or hidden.
The CSS is used to show or hide the links.

I already mentioned that I have a few additional lines of code in the actual page.js used on my site, to be able to mark <div>s that shall not be automatically hidden once the page is loaded. It did not include this in my description in this post to not confuse you. But, if there’s interest, I’ll gladly write a second post on this! Just tell me.

If you have any questions, please feel free to ask or leave a comment! Also feel free to use the code whereever you like. Please keep in mind though, that I can not give support if you want to add this to your site. I just don’t have the time. Thanks for your understanding.

And one more recommendation: If you want to do this on your site, I strongly advise to use the “HTML editor” in WordPress and NOT the “visual editor” (called TinyMCE) as it most certainly will break the HTML that we need.

If you find this post useful, why not have a look at my wishlist or make a donation?

Bookmark this page on:
  • email
  • PDF
  • Print
  • RSS
  • Digg
  • del.icio.us
  • Facebook
  • Twitter
  • Technorati
  • StumbleUpon
  • Google Bookmarks
  • Reddit
  • MisterWong
  • NewsVine
  • Yigg
  • LinkArena
  • LinkedIn
  • Live
  • MySpace
  • Slashdot
  • Webnews.de
  • Wikio
  • FriendFeed
  • Yahoo! Buzz

25 comments

  1. oko says:

    Klasse! Werde mich jetzt mal durcharbeiten und versuchen das umzusetzen. Dank jedenfalls schonmal für Deine Anleitung.

    • Jan says:

      Kann es sein, dass Themes keine page.js haben? Finde hier z.B. nur ein page.php, mehr aber auch nicht.

      • Tobias says:

        Hi,

        absolut richtig, ist im Text ein bißchen blöd formuliert.
        Die page.js musst du selbst anlegen (mit dem Code von oben). Ich empfehle, sie mit im Theme-Ordner zu speichern, weil das ganze ja schon zum “Aussehen” der Seite zuzuordnen ist. Außerdem findet man sie dann leichter :-)

        Gruß
        Tobias

        • Ooch says:

          Scheint zu klappen, allerdings werden bei mir “epand” und “hide” einfach am Rand des Browsers angezeigt (wirklich ganz rechts, also außerhalb meines Blogs). Kann man das nicht irgendwie begrenzen? Mein Blog ist z.B. 760 Pixel breit also, so, dass expand und hide maximal am Rand angezeigt werden (wie die gestrichelten Linien, diese werden richtig angezeigt).

          Gruß
          Ooch

          • Tobias says:

            Hi,

            die Positionierungsgeschichte ist u.a. mit abhängig von der Art (“relative” oder “absolute”). Also eventuell mal beim CSS für h3 span an den Werten “position” und “right” rumspielen.
            Mehr dazu z.B. unter http://www.css4you.de.

            Gruß
            Tobias

  2. oko says:

    @Tobias:
    Ich werd irre, finde einfach den Fehler nicht, habe jetzt schon alles durch. Wie hast Du es denn geschafft das “Expand” und “Hide” so zu positionieren, dass es innerhalb der Spalte bleibt?

    • Tobias says:

      Hi,

      also eigentlich mach ich nichts weiter als das oben erwähnte… Eventuell hilft es noch, wenn du dem <div>, welches den Inhalt enthält, auch ein “position:relative;” verpasst.

      Wenn du mir den Link zu deiner Seite schickst, kann ich auch mal drüber gucken, ob ich was finde.

      Gruß
      Tobias

      • oko says:

        So, also, haben nun folgendes gemacht und einigermaßen hinbekommen: wie du schon erwähntest “position:relative;” und bei “right”:-620px;” soweit so gut. Jetzt wird das expand in einer 760px Spalte fast korrekt angezeigt. Sobald ich jedoch eine weitere Zeile, also Expand/Hide setze (z.B. “Heading 2″), wird das “expand” dann je nach Länge des Textes bzw. Wortes am Anfang anders angezeigt.

        Gibt es denn da eventuell eine Einstellung, dass das automatisch erkennt wie breit die Spalte ist und entsprechend anzeigt und das bei allen folgenden Bereichen? Bei der gestrichelten Linie klappt das ja auch.

        An dieser Stelle nochmals echt klasse, dass du dir die Zeit und Mühe machst. Hast mit Sicherheit nicht nur einen neuen Stammleser deines Blogs gewonnen :-)

        • Tobias says:

          Hi,

          statt mit “right” könntet ihr eventuell auch mal mit “left” experimentieren. Sollte eigentlich auch gehen und liefert vielleicht bessere Resultate bei anderen Bildschirmauflösungen, etc.

          Von einer Einstellungen, wie du sie suchst, weiß ich leider nichts. Ich bin da auch eher der “Trial&Error”-Typ :-)

          Aber wie gesagt, wenn du mir die URL zu eurer Seite gibst, kann ich mal gucken. Ohne Seite ist das ganze mehr wie Wahrsagen mit einer Glaskugel :-)

          Gruß
          Tobias

  3. life so nice says:

    Hi, Tobias
    This feature is really great!
    Thanks!

  4. Daniel says:

    Bei mir funktioniert es leider nicht. Ich habe nur eine gestrichelte Linie über Heading 1 und der Inhalt wird direkt angezeigt. Fahre ich mit der Maus über Heading 1 wird zumindest schonmal ein Handsymbol angezeigt, aber beim klicken passiert nichts.

    Woran könnte es liegen?

    • Tobias says:

      Hi Daniel,

      so aus der Ferne kann ich leider nicht sagen, wo der Fehler liegt. Ich vermute, dass die JavaScript-Dateien nicht richtig eingebunden sind oder nicht geladen werden.

      Gruß
      Tobias

  5. Zac says:

    Hallo Tobias,

    ich habe mal versucht, das auf unserer Seite einzubinden, nur leider scheint es nicht so ganz zu funktionieren. Beim Laden der Seite wird der Inhalt angezeigt, wenn es dann fertig geladen ist, ist alles zugeklappt. Klicke ich nun drauf, passiert nichts weiter, expandhide wechselt zu hide und das wars?!

    • Tobias says:

      Hi Zac,

      bei dir sieht es im Quelltext so aus, als ob das h9 noch innerhalb eines p steht. Vermutlich liegt das daran, dass bei dir das h9 durch eine Leerzeile vom div getrennt ist. WordPress macht daraus dann ein p.
      Außerdem muss das CSS natürlich übernommen werden.

      Könntest du das bitte nochmal prüfen?

      Gruß
      Tobias

      • Zac says:

        Ich habe mal eine neue Seite dafür angelegt, es funktioniert jetzt. Nur steht Expand und Hide ganz rechts außen und ich habe nicht den Rahmen, wie in deinem Beispiel. Wüsste aber nicht, woran es liegen kann.

        Danke für deine Hilfe

        • Tobias says:

          Hi,

          prima, dass es jetzt klappt. Der Rest sind nur noch kleine CSS-Geschichten. Um “Expand” und “Hide” nach innen zu holen, muss einfach beim CSS der Klasse “.entry” noch ein “position:relative;” hinzugefügt werden.

          Der blaue Rahmen in meinem Beispiel ist eigentlich nur zur optischen Abtrennung gedacht gewesen :-) Aber wenn du den noch möchtest, musst du einfach den jetzigen HTML-Code noch in ein neues div packen, welches per CSS den Rahmen bekommt.

          Gruß
          Tobias

          • Zac says:

            Also, es klappt soweit jetzt alles, nur ich würde es gern so haben, dass alle Expire bzw. Hide direkt untereinander stehen. Kann man das auch irgendwie hinbekommen?

            Und noch eine zweite Frage: Kann ich das Expire und Hide einfach in Aufklappen und Verstecken umbenennen oder sind das Variablen, die nicht verändert werden dürfen?

          • Tobias says:

            Hi,

            ja, das geht. Ich konnte das leider nicht mit in den Artikel schreiben, weil es teilweise stark von der Seite/dem Theme abhängt. Bei dir könntest du folgenden CSS-Code (statt des jetzigen) probieren:
            /*=== Aufklappen unter Sprachenliste ===*/
            h3 {padding-top:10px; cursor:pointer; position:relative;}
            h3 span {display:none; position:absolute; left: 375px; font-size: 12px; color: gray;}
            h3.slidehidden .expand {display:inline;}
            h3.slidehidden .hide {display:none;}
            h3.slidevisible .expand {display:none;}
            h3.slidevisible .hide {display:inline;}

            Und natürlich kannst du Expire und Hide umbenennen. Die ensprechende Stelle findest du in der JavaScript-Datei page.js. Dort dürfen jedoch nicht die Klassennamen umbenannt werden.

            Gruß
            Tobias

  6. Zac says:

    Grandios,

    du bist der Beste :-)

    Sag mal, programmierst du auch gegen Auftrag? Du scheinst es ja richtig gut drauf zu haben.

  7. Jose Miguel says:

    Thanks a lot for this tutorial!

  8. Deanna says:

    Hello Tobias,

    I am trying to use this tutorial for the accordion expand/hide feature on this page of my site: http://deannasquest.com/resources/

    I have added the first two lines of script into both the end of the post as well as in the page.php file.

    I created the page.js file using the script listed.

    And I added the CSS script to my style.css file.

    I am not getting the expand/hide buttons or the expanding function. I am new to JavaScript and fairly new to CSS, PHP, and WordPress, so it is extremely likely that I am doing something very wrong. If you could take a peek at it, to see if you can figure out what I’m doing wrong.

    BTW, I am using WordPress 3.0.1 and the latest versions of both Firefox and Safari on OS X.

    Thank you so much for your help.

    Deanna

    • Tobias says:

      Hi Deanna,

      thanks for your comment.

      When I tried yesterday, the expand/hide feature worked (except for the showing of the actual text “expand”/”hide”). Today it no longer works, so I assume that you have added some other JavaScript meanwhile?

      One first fix would be the positioning of the labels. For that, please add the following to the CSS code:

      #content .post .post-entry {
        position: relative;
      }

      Regards,
      Tobias

  9. Andrew says:

    Any chance in the future to implement the “expand” like on this page: http://www.exa-bytes.com/webhosting/ in the plugin? It looks very nice! :)