jQuery Expandable Max List Items (LI)

This jQuery plugin will automatically hide all excess list items past a maximum number. It then dynamically adds an expand/collapse link that uses the slideToggle effect. Each list item is collapsed in succession to give the appearance of using slideToggle on a container. The max number, speed of animation, and expand/collapse HTML can be passed as options. The full unordered or ordered list appears as normal when JavaScript is disabled.

hideMaxListItems Usage and Options

The jQuery plugin isn’t very large, so you could paste the code into your existing JavaScript file to reduce HTTP requests. Or you can do it the easy way and just download the JS file and include it on your page like so:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="/yourJavascriptFolder/hideMaxListItem.js"></script>

Then you can call the plugin. Here’s a basic example:

$(document).ready(function() {
	$('#elementToApplyHere').hideMaxListItems({ 'max':4 });
});

There are a few available options; the maximum number of list items to show, the speed of the slide animation in milliseconds, the HTML used for the expand/collapse link, and the text within this link.

It defaults to a max of 5, a speed of 1000 (ms), and a paragraph containing a link with “READ MORE”. Note that the expand/collapse container needs the “maxlist-more” class, and a child anchor tag. Here’s an example with the options:

How slideToggle() works on multiple LI tags

I’ve you’ve ever applied jQuery’s slideToggle function to a bunch of LIs, you may have noticed the resulting effect may not have been what you were going for. By default, each individual LI tag will collapse on its own. It looks like you’re turning the blinds on a window.

Part of what this plugin does is to hide each list item one by one (using a great sequential animation technique). This way, it looks just like you are applying slideToggle to a single div and the HTML stays valid (this isn’t easier because ULs and OLs do not allow any other kind of separating block element as a direct descendant).

To allow the speed option of the whole effect, I divide the speed by the total number of hidden list items. This gives the speed of each individual list item’s animation.

Plugin Source Code

Download the latest version from GitHub:

Comments on this Article

  1. Vert Studios says:

    Yeah, so jQuery is pretty much the most kickass thing happening with JavaScript right now.

  2. Christine says:

    Thank you for script. Since I am completely new to Jquery as well as Javascript, can you tell me how to make this script work nicer, I mean if i click READ MORE on the list which is at the bottom of page, I am being relocated to the top of the page even though list expands, but don’t think this is nice for user interface. Any help will be appreciated

    • Josh says:

      Thanks for bringing this up. I didn’t notice since it’s the whole height of my screen. This is because the links are set to “#” which will bring you to the top of the page. You can prevent by using an empty HREF attribute on the anchor tag, or by using event.preventDefault() to stop # from scrolling: http://api.jquery.com/event.preventDefault/

      I will make an update in the next version.

  3. mihai says:

    I think in my last comment something was missing from my example. So I am posting again…
    I am looking for a way by clicking the read more button to expand current list but collapse the rest.

    Somethig like this:

    LIST 1

    – element 1
    – element 2
    – element 3
    – element 4

    [READ MORE BUTTON 1]

    LIST 2

    – element 1
    – element 2
    – element 3
    – element 4

    [READ MORE BUTTON 2]

    LIST 3

    – element 1
    – element 2
    – element 3
    – element 4

    [READ MORE BUTTON 3]

    And after click on read more button 1, 2, or whatever display like this:

    LIST 1

    – element 1
    – element 2
    – element 3
    – element 4
    – element 5
    – element 6
    – element 7
    – element 8

    LIST 2

    [READ MORE BUTTON 2]

    LIST 3

    [READ MORE BUTTON 3]

    After click on let’s say button 2 show like this:

    LIST 1

    [READ MORE BUTTON 1]

    LIST 2

    – element 1
    – element 2
    – element 3
    – element 4
    – element 5
    – element 6
    – element 7
    – element 8

    LIST 3

    [READ MORE BUTTON 3]

    Some ideas?
    Thanks!

    • Josh says:

      mihai – This sounds a little bit more like an accordion type of functionality, since they are fully collapsing. Hmm. That makes it a bit more complicated. It might be better to start with an accordion script, and show the first few bullets when the page first loads, if that’s the only time it will show them in that format. Otherwise I suppose you could edit the children(“a”).click function to collapse all other lists and no longer use the max option.

  4. mihai says:

    Hy Josh,
    I have done this:
    // Get array of children past the maximum option
    var listElements = $(this).parent().prev(“ul, ol”).children(“li”);
    listElements = listElements.slice(op.max);
    $(‘ul li’).slideUp(‘normal’)

    Added $(‘ul li’).slideUp(‘normal’) inside children(“a”).click function.
    This is fine, but is opening only li that were previosly closed.

    Example:
    LIST 1

    – element 1
    – element 2
    – element 3
    – element 4

    [READ MORE BUTTON 1]

    LIST 2

    – element 1
    – element 2
    – element 3
    – element 4

    [READ MORE BUTTON 2]

    on click the read more button returns this:

    LIST 1

    – element 5
    – element 6
    – element 7

    [READ MORE BUTTON 1]

    LIST 2

    [READ MORE BUTTON 2]

    Have any idea for fixing this to display all the elements?
    Thank you very much!

  5. mihai says:

    I have done it:

    Here’s the code needed for adjustments if someone else need my solution:

    After:

    // Get array of children past the maximum option
    var listElements = $(this).parent().prev(“ul, ol”).children(“li”);
    listElements = listElements.slice(op.max);
    listElements = listElements;

    Add this:

    $(‘ul li’).slideUp(‘normal’);

    And uncomment:

    //listElements = listElements.slice(op.max);
    //listElements = listElements;

    Your final code shoud look like this:

    // Get array of children past the maximum option
    var listElements = $(this).parent().prev(“ul, ol”).children(“li”);
    //listElements = listElements.slice(op.max);
    //listElements = listElements;
    $(‘ul li’).slideUp(‘normal’);

    Would be great if onclick the max variable could be changed to o 0 value also but I didn’t manage to do this.
    This could be usefull if we have a list with less values than our max. If that would be
    If someone can make a hack fro that and post here would be great.

    Thanks!

  6. Stewart says:

    Do you have any advice on how to add a text toggle to this? For instance, when you click “Show More,” the text toggles to “Show less.” I have tried adding toggle functions, but it is either ignored or it breaks the script. Thanks.

    • Josh says:

      Hello Stewart – I’ve just updated the code on Github to version 1.2, which now allows the option to change this text.

    • Josh says:

      This is fixed and updated to version 1.3. Thanks.

  7. Hali says:

    How about showing the hidden items count?

    For example instead of the text show more could it say: There are 10 more items…

    Can that be done?

    • Josh says:

      I’ve added this feature to 1.31 on github. You can now include [COUNT] in the “moreText” option, and it will be replaced with the number.

  8. Dan says:

    Hi,

    Great plugin, can you help me to keep the list expanded after you go to another page in case you clicked to expand the list on a previous page?

    For example, lets say I have 2 lists that shows on all pages of my site, when I click to expand one of the lists and go to another page the lists will not be expanded, I would like to keep the list expanded in all pages in case you have clicked to expand it before. Can you help me?

    Thank You!
    Dan

    • Josh Winn says:

      Hello Dan- I’m not planning to add that feature, but you would have to add code to store a cookie, and then if that cookie is set on page load, expand the necessary list(s) (I’d trigger() click since there’s no public method at the moment). You’d probably need to store what elements are clicked in the cookie, so you can target them again.

  9. Anthony says:

    Hi Josh, thanks for a great plugin. I’m wondering if I can apply the jquery .on() functionality to this. I have lists which are dynamic in the sense they are added to and deleted by ajax calls with resulting remove and prepends and as such I wanted the list to update with the max row plugin to fire again to ensure only the specified number of list items remain. I can’t manage to get this to work at the moment. Any ideas would be really appreciated. Ant

    • Josh Winn says:

      For the next version I’ll look into adding the ability to have it update (perhaps a method) for cases where you’re removing or adding elements from the DOM.

      • Ricardo says:

        Hi Josh, I would like to ask you if you have any update about this feature? (about Anthony wrote)…or if you have any suggestion to apply here?
        Thanks for your time and contribution!!!

        • Josh says:

          I’ll put this on my to-do, and get this updated as soon as I have a free moment. Hopefully within a week, possibly this weekend.

        • Josh says:

          I’ve updated the plugin to version 1.36, which now can work with dynamic content changes. I’ve added a test of adding and removing list items to the example HTML file, and have put a note on the README.

  10. Brian says:

    Hey Josh, great plugin! Have you set up a license for this?

  11. Björn says:

    Hi Josh, thanks for a great plugin!

    I would like to to style my moreText and lessText in different ways, but I can’t think of a way to do that right now since no class is added when you click the more link.

    I tried adding span tags to the moreText/lessText variables but noticed they are just interpreted as strings.

    Any ideas how I could solve this?

    • Josh says:

      I’ve just updated the plugin to 1.35, which now allows you to use HTML in those options. So you can use the SPANs like you had attempted.

      • Björn says:

        Thanks Josh, that was unbelievably quick! 🙂 Works like a charm!

  12. Vivian says:

    This is great!
    How can i add different icons to “Read more” and “Read Less”?
    Please help!

    • Josh says:

      You can use HTML in the ‘moreText’ and ‘lessText’ options. For example, if you were using FontAwesome, you could do something like

      'moreText': '<i class="fa fa-plus-circle" aria-hidden="true"></i> MORE'
  13. Shariq says:

    Hi Josh, thanks for a great plugin!

    Is it possible that max value becomes automatic according to its parent width and height?

Leave a Reply

You can use the <pre> tag to post a block of code, or <code> to highlight code within text.