« Photo Sharing | Main | Keeping an Entry at the Top »

Expandable List Menus

If you have a lot of content - entries, categories, sidebar information - sooner or later things may begin to look a little cluttered on your weblog. One way to address this is to make some of your lists expandable and collapsible, as I have done with LMT's Table of Contents. There are probably many different ways to do this. I have found one method, based on Javascript, that is simple to implement and appears to work fine, from Bleeding Ego.


1. Upload listmenu.js to your server.

Copy the following script into a new file with a texteditor. Save the script as "listmenu.js". Upload the script to a location within the public directory of your server using an FTP program. (You can also find a copy of this script at Bleeding Ego.)

/*
Expandable Listmenu Script
Author : Daniel Nolan
http://www.bleedingego.co.uk/webdev.php
*/

function initMenus() {
if (!document.getElementsByTagName) return;

var aMenus = document.getElementsByTagName("LI");
for (var i = 0; i < aMenus.length; i++) {
var mclass = aMenus[i].className;
if (mclass.indexOf("treenode") > -1) {
var submenu = aMenus[i].childNodes;
for (var j = 0; j < submenu.length; j++) {
if (submenu[j].tagName == "A") {

submenu[j].onclick = function() {
var node = this.nextSibling;

while (1) {
if (node != null) {
if (node.tagName == "UL") {
var d = (node.style.display == "none")
node.style.display = (d) ? "block" : "none";
this.className = (d) ? "treeopen" : "treeclosed";
return false;
}
node = node.nextSibling;
} else {
return false;
}
}
return false;
}

submenu[j].className = (mclass.indexOf("open") > -1) ? "treeopen" : "treeclosed";
}

if (submenu[j].tagName == "UL")
submenu[j].style.display = (mclass.indexOf("open") > -1) ? "block" : "none";
}
}
}
}

window.onload = initMenus;


2. Add a script reference line to the header of your index or archive template.

In the header section of the templates in which you want the expandable list menu to be used, add the following line:

<script src="http://www.your_web_site.com/path/to/listmenu.js" type="text/javascript"></script>

Replace the "http://www.your_web_site.com/path/to/" with the actual path on your server to the listmenu.js that you uploaded to your server in step one above.

3. Insert your list into your template or document using the following structure:

<ul class="treemenu">
<li class="treenode">
<a href="">Top Level Item</a>
<ul>
<li><a href="">List Item</a></li>
<li><a href="">List Item</a></li>
<li><a href="">List Item</a></li>
<li><a href="">List Item</a></li>
</ul>
</li>
</ul>


Note in particular the lack of a symbol between quotation marks in <a href="">

For example, here is a snippet of code that I use on my Table of Contents template:


<ul class="treemenu">
<li class="treenode">
<a href=""><h2>Beginner Tips</h2></a>
<ul>
<MTEntries category="Beginner Tips" sort_by="title" sort_order="ascend">
<a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a><br />

</MTEntries>
</ul>

<a href=""><h2>Categories</h2></a>
<ul>
<MTEntries category="Categories" sort_by="title" sort_order="ascend">
<a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a><br />
</MTEntries>
</ul>
</li>
</ul>

This code requires that you specify each category and give it a name. I've done this with my Table of Contents so that I could list out the contents in the specific order I wanted. If you want to simplify this process and list out your TOC in the ascending order of your categories, try the following code (suggested by Arvind from Movalog):

<ul class="treemenu">
<MTCategories>
<li class="treenode">
<a href=""><h2><MTCategoryLabel></h2></a>
<ul>

<MTEntries><li><a href="<MTEntryPermalink>"><MTEntryTitle>
</a></li></MTEntries>
</ul>

</MTCategories>
</li>

</ul>

4. Add ListMenu stylesheet elements to your stylesheet.

You can style your list by adding some style elements to your stylesheet. See listmenu.css for an example of some css elements to add to your stylesheet from Bleeding Ego. Here are the style elements I've added to the stylesheet for the Table of Contents in LMT:

.treemenu {
margin : 0px 20px;
padding : 10px;
list-style : none;
}

.treemenu h2
color: #004090;
font-family: 'Trebuchet MS', Verdana, sans-serif;
font-size: small;
text-align: left;
font-weight: bold;
margin-top: 5px;
margin-bottom: 5px;
}

.treemenu UL {
list-style : none;
}

.treemenu LI {
display : inline;
}

.treemenu A {
text-decoration: underline;
}

The best place to add these style elements is at the very bottom of your stylesheet.

(Note the only real problem I encountered with this script was in Safari. The Table of Contents index template still had RSS header information in the header. For some weird reason these lines interfered with the Safari browser when the script was loading for the first time, with the result being a lot of odd text added to the page. Removing the RSS, Atom, and RSD link rel lines from the TOC template resolved the problem.)

Comments (23)

elise:

If the user's browser does not support Javascript, the menu should show up as all expanded. In case this doesn't happen, I've included a link to a section of the Index page (Master archive list) that has the entries sorted out by category. I find it much easier to look at the section titles without having to scroll forever through every entry title.

You can improve the code you use on your Table of Contents page..rather than manually listing out each h2 and then the entries underneath it try out this

<ul class="treemenu">
<MTCategories>
<li class="treenode">
<a href=""><h2><MTCategoryLabel></h2></a>
<ul>
<MTEntries><li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li></MTEntries>
</ul>
</li>
</MTCategories>
</ul>

it should produce the same code, just one block of it now rather than x (number of categories) blocks!

frostdoll Author Profile Page:

I just want to let you know that the last code posted by Arvind misses a tag

<a href=""><h2><MTCategoryLabel></h2> </a>

Otherwise the script doesn't work.

Note from Elise: Missing closing A tag added into Arvind's code in his comment. Thanks for the catch. ~Elise

Sithicus:

Has anybody gotten this this same script or something simliar to work with so it goes one more level deep.

ex//
Entertainment

kumaran Author Profile Page:

In the code snippet provided by Arvind, the following two lines need to be swapped in their order:

<li class="treenode">
<MTCategories>

Otherwise, only the first category has a list-item marker. The corresponding two lines closing these tags also need to be swapped.

Note from Elise: I swapped these as recommended in Arvind's code text in his comment. Thanks for the suggestion. ~Elise

Olivier Severyns:

When I click on an entry in an expanded category, the menu collapses back on the new page : is it normal ? I wish the menu for the current category would stay expanded while viewing the entry. Any suggestion ?
Thanks for this very helpful site !

Bud Parr Author Profile Page:

Elise - I use both MT and TypePad Pro (which is similar to MT in tags and such), and I want to say that your site is incredibly helpful.

I just implemented the technique above on my TypePad sites on the categories to save space, but also in a couple of other areas. I put some Bloglines script in there to hide my burgeoning blogroll and I've used it in my comments section.

I had long wanted to have comments more accessible to readers. This was the solution. I created the list just as above, but inserted the comment tag and put it at the bottom of my entries section. There may be an easier way, but this worked for me.

Thanks very much!

Thank you for a great web site! I added this to a site I am helping a friend with and I somehow it does not work with the archives. Also, does anyone know how to make this work for a list of subcategories? So categories --> subcat --> list of articles?
Thanks a bunch...and btw - the site I am working on is www.blogbridge.com/index2...an open source project.

sk:

I just want to have a sub-category collapsible, i.e sub-sub-category menu items expand/collapse. I do not want to list entries at all in the collapsible menu. Would anyone know the code for that?

Thanks and thanks elise for a wonderful site.

dannyFoo Author Profile Page:

I found a website called, Quirks Mode and he's got a script that enables you to add a deeper level to the collapsible menu. Visit his website at www.quirksmode.org and navigate to:

Javascript > DHTML > Navigation:display

Might require some understanding of JScript to be implemented though.

Cheers. :)

paul:

I have created a collapsing nav menu using CSS, this is my first time trying such a task and was wondering how I can keep the nav menu open when I proceed to the linked page. I read your comments above and cannot seem to apply them to my code.
Here is my code, any suggestions on how to do this would be greatly appreciated!

style type="text/css" media="screen"

body {
margin: 0;
padding: 0;
background color: #d1daec;
font-family: helvetica;
font-size: 0.6em;
font-weight: bold;
}
#dl, dt, dd, ul, li {
margin: 0;
padding: 0;
list-style-type: none;
white-space: normal;
}
#menu {
position: static; /* Menu position that can be changed at will */
top: 105;
left: 2;
}
#menu {
width: 12em;
}
#menu dt {
cursor: pointer;
margin: 0;

line-height: 15px;
text-align: left;
font-weight: bold;
border: #d1daec;
background: #d1daec;
}
#menu dd {
border: #d1daec;
}
#menu li {
text-align: left;
background: #ffffff;
}
#menu li a, #menu dt a {
color: #d1daec;
text-decoration: none;
display: block;
border: 0 none;
height: 100%;
}
#menu dt a:hover {
background: #ffffff;
}
#menu li a:hover {
background: #d1daec;
}

/style

script type="text/javascript"

window.onload=show;
function show(id) {
var d = document.getElementById(id);
for (var i = 1; i

Perry:

I can't get Arvinds solution to work in MT 3.2
Is it not possible to do this in the alpha-part of the MT-site? In the left sidebar?

Has anyone done anything to get subcategories working in this manner?

Implementing Arvind's suggestion, above, I've got all of my categories and subcategories in one big list...clicking on any of them gives me a list of the entries in them.

What I thought should happen would be that you'd click on a category, and then get a list of any entries for just that category, and then the list of subcategories. Clicking on the subcategories would then give you the entries for the subcategories and then more subcategories (if you're nesting that far).

i.e.

*Parties
*Visits
*Misc

Click Parties

*Parties
*Birthday
*Holiday
Dad's Retirement (this would be an entry under "Parties, but not under the subcategories)
*Visits
*Misc

Click on Birthday
*Parties
*Birthday
Dad
Mom
Son
*Holiday
Dad's Retirement
*Visits
*Misc

Etc.

Has any work been done in this area?

Thanks.

Chris:

Why doesn't this code work? It's driving nuts. The script is properly linked on the page but this code still doesn't work.

<div class="category-menu">
<ul class="treemenu">
<li class="treenode">
<MTTopLevelCategories>
<a href=""><MTCategoryLabel></a>
<ul>
<MTSubCategories>
<li>
<MTIfNonZero tag="MTCategoryCount">
<a href="<$MTCategoryArchiveLink$>"><$MTCategoryLabel$></a>
<MTElse>
<$MTCategoryLabel$>
</MTElse>
</MTIfNonZero>
</li>
</MTSubCategories>
</ul>
</MTTopLevelCategories>
</li>
</ul>
</div>

Thanks for any help.

Hi all,

I am completely winging it when I implement code like this. It's all trial and error. Sorry I can't be of more help. You might consult someone who knows something about javascript and CSS.

Regarding the stray bullet point, I finally figured that out. Needed to add this in the CSS:

.treemenu LI {
display : inline;
}

This code still works fine for me with MT3.3 by the way.

Jim:

FYI - I had problems getting this to work. After much hair-pulling, I tracked it down to the example above:

(3rd example under Step #3)

<a href=""><h2><MTCategoryLabel></a></h2>

Note the "</a>" is nested inside the closing "</h2>" - it needs to be outside for the script to work. Like so:

<a href=""><h2><MTCategoryLabel></h2></a>

At least, that fixed my problem.

Is there some way this method could work with monthly archives?

Hi Jim,
Oh, I hate little bugs like that. Thanks for the catch.

Hi Joanna,
I don't know of any method. I don't recommend monthly archives (too much rebuilding) and wouldn't recommend using something like this with them.

Works! I do many things using the trial and error method and this short tutorial likely saved me a morning of figuring it out myself. Thank you!

SK and Sithicus, sorry for being two years late, but maybe you're still interesting or maybe others are. My request was similar to yours in that I only wanted to see subcategories, and not entries within sub-categories. I also wanted more than one level of subcategories. What I was able to come up with was of the form:

RootCategory opens all Subcategories.

In this fashion I think I was half successful in the final result. By that I mean top level categories are collapsed and when clicked on open up the sub showing ALL subs. This is not the full result, but it does save space. To get a clear idea, test this code:

<MTIfArchiveTypeEnabled archive_type="Category">
<div class="module-categories module">
<h2 class="module-header">Categories</h2>
<div class="module-content">
<ul class="treemenu">
<li class="treenode">
<a href=""><img src="/images/li-bg.gif" alt="icon" /></a>Technology
<MTTopLevelCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li class="module-list-item-tree"><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a></li>
</MTIfNonZero>
<MTSubCatsRecurse>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTTopLevelCategories>
</li>
</ul>
</div>
</MTIfArchiveTypeEnabled>

There is manual labor required in that you have to input the top level category for every root or top level category you have. So this means where I have Technology listed as my root category above, you should change yours to your top most category. Also, set your image path correctly. This little .gif I placed was from theme-beckett. Whichever theme you're using, just find the module-list's icon.

And finally, adjust your css in this way:
1)Open your css where you placed .tree and change its rules to:
.treemenu 
{
margin : 0px 0px;
padding : 0px;
list-style : none;
}

2)Open the theme's css and find module-list-item. Right below it make this rule which I included in the code above please notice it:
.module-list-item-tree 
{
padding-left: 14px;
margin-left: -60px;
background: url(li-bg.gif) 0 .3em no-repeat;
}

margin-left: -60px; is not considered solid css, however I didn't spend much time on the css. I just wanted it to look as close as possible to my existing theme and therefore yours to get the effect of what I was able to code concerning the categories.

Mostly, it's a conglomerate of Elise's and Chad's techniques. This will be available to view on my site once it's fully up and running and if someone can find a way to collapse the sub's that'd be great.

-Patrick


Hi Patrick -

If I follow, the problem is that your subcategories aren't collapsed? If so, take a look at this:

<MTSubCategories>
<MTSubCatIsFirst><ul class="treemenu"></MTSubCatIsFirst>
<li class="treenode">
<MTHasNoParentCategory><MTElse>» </MTElse></MTHasNoParentCategory><a class="treeclosed" href=""><MTCategoryLabel> (<$MTSubCatCount category="1"$> Categories, <$MTSubCatCount$> Entries) <img src="/right.gif" class="closed" height="7" width="4" alt="" /><img src="/down.gif" class="open" height="4" width="7" alt="" /></a>
<ul style="display: none; padding-top: 10px;">
<MTSubCatsRecurse max_depth="3">
<MTEntries>
<li class="treesubnode"><a href="<MTEntryPermalink>"><MTEntryTitle></a> (<$MTEntryDate format="%x"$>)</li>
</MTEntries>
</ul>
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTSubCategories>

It's not exactly the same as yours (notable, I use "treesubnode" rather than "module-list-item-tree", but hopefully it's close). I use this on a number of sites, and the subs are always collapsed. Hopefully it will help!

andy:

in MT what file to I add the script reference and where do i paste the list code

Hi Andy,
What version of MT are you using? I wrote this tutorial almost 4 years ago, I have no idea if it works with MT4, though it should. In MT4 you add the script reference to the header section of your template on which the list will appear. In MT4, you can find your header module in the template modules. In earlier versions of MT you need to add this to the header section of the individual templates. By header I mean the part between the <head> and </head> tags.
As for where to put the list code, you put it wherever you want the list to appear. So if you want a special page just to show off this list, you need to create a page or a template and put the list code in it.

Post a comment

(If you haven't left a comment here before, your comment may need to be approved before will appear on the entry. Thanks for waiting.)