"Innovation comes only from readily and seamlessly sharing information rather than hoarding it."- Tom Peters
Development Blog

Collapsible Fieldsets jQuery plugin - Drupal Style

Drupal does a great job in using collapsible fieldsets.  But, wouldn't it be great to be able to use this jQuery feature on other sites?  Well, here's your plugin.  In this tutorial, we will build a simple page, and then enable the collapsible fieldset on it.


Well, let's get started. First, let's make a simple HTML page to start with.


<h1>Collapsible Fieldset - jQuery plugin</h1>
<fieldset>
<legend>Cannot collapse me</legend>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in nisi magna.</p>
</fieldset>
<fieldset class="collapsible">
<legend>Can Collapse Me!</legend>
<h2>1914 translation by H. Rackham</h2>
<p>"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment...,"</p>
</fieldset>

You'll notice that the first fieldset has no class, while the second one has a class of collapsible. We will be using this later on. You'll also want to go ahead and include the javascript source file for jQuery.

The jQuery plugin

Now, let's take a look at the actual plugin. What makes it work? How's it do it? Well, let's find out!


$.fn.collapse = function() {
return this.each(function() {
$(this).find("legend").addClass('collapsible').click(function() {
if ($(this).parent().hasClass('collapsed'))
$(this).parent().removeClass('collapsed').addClass('collapsible');

$(this).removeClass('collapsed');

$(this).parent().children().not('legend').toggle("slow", function() {

if ($(this).is(":visible"))
$(this).parent().find("legend").addClass('collapsible');
else
$(this).parent().addClass('collapsed').find("legend").addClass('collapsed');
});
});
});
};

Alright...jQuery makes it super easy to create your own functions, and add them right into the framework. The only thing that is required is the next line. This line of code ensures the ability for jQuery to chain together many functions. It allows you to do something like this:

$("p").css("color", "#0000FF").find("a").slideUp();

Now, I'm not sure why you would want to do a function like that, but you can if you include that line of code.

The third line of code selects the fieldset's legend, adds the class collapsible to it, and then creates the onclick function. Let's take a look at that...


if ($(this).parent().hasClass('collapsed'))
$(this).parent().removeClass('collapsed').addClass('collapsible');

$(this).removeClass('collapsed');

This part of the code checks to see if the parent (the fieldset) is currently in the collapsed state. If so, go ahead and add the 'collapsible' class. Now, why are we doing this? This ensures that the fieldset borders will be shown (if you style it to do so) DURING the animation, and not just have them appear once it's done.


$(this).parent().children().not('legend').toggle("slow", function() {

if ($(this).is(":visible"))
$(this).parent().find("legend").addClass('collapsible');
else
$(this).parent().addClass('collapsed').find("legend").addClass('collapsed');
});

This section of the code selects the fieldset, then its children, selects everything that is not the label, and then toggles it (does the animation of opening or closing). Now, if you notice that you are using an element not contained in this set, feel free to add it! Once the toggle is complete, the callback function is called to ensure the fieldset and legend are in their proper states. Pretty simple, huh?

The CSS

Now that we have our page and plugin, lets add some styling to it. I'm going to keep this VERY basic, but feel free to do whatever you want.


fieldset, fieldset.collapsible {
padding: 10px;
border: 1px solid black;
border-bottom-width: 1px;
border-left-width: 1px;
border-right-width: 1px;
margin-bottom: 1em;
}
fieldset.collapsed {
border-bottom-width: 0;
border-left-width: 0;
border-right-width: 0;
margin-bottom: 0;
margin-left: 3px;
}

legend.collapsible {
color: blue;
}
legend.collapsed {
color:green;
}

Putting it all together

Now that we have the HTML, the plugin, and the CSS, let's put it all together, and make this thing work! All you have to do now is select the elements you want to collapse, and make them work! Here's a sample...


<script type="text/javascript">
$(document).ready(function() {
$("fieldset.collapsible").collapse();
});
</script>

Now that you have your page, put it to work! Test it out! Let me know how it goes! Of course, this plugin currently doesn't have any configurable options. Feel free to let me know what you might want! I'll try to implement them as quickly as I can! Thanks!


UPDATE: Version 1.1 (and 2.1) have been released. The only change is the fieldset is now toggled using .not('label'), rather than .filter( ELEMENTS ). This will allow you to place anything you want in the fieldset, without having to limit to these elements. Thanks emichan for the tip!

UPDATE: I've added another version of the plugin below (v2.1). It allows you to initiate the fieldsets, and have certain ones closed. In order to do so, use something like this... (I've got the first line starting open, and the second line being closed. Just change the class for the fieldset).


$(document).ready(function() {
$("fieldset.collapsible").collapse();
$("fieldset.collapsibleClosed").collapse( { closed : true } );
});

UPDATE: Version 2.1.2 fixes an issue when nested fieldsets are used.

UPDATE: Version 2.1.3 makes the script $.noConflict() compliant. I will no longer update the original script that this tutorial made, but will still make it available below. I will do updates on the current release though.

AttachmentSize
Original Script968 bytes
jquery.collapsible-v.2.1.3.js1.43 KB

Anthony's picture
Nov 5, 2009
6:34 pm
Anthony

This demo works great however when I add this code to my JSP and I use the collapsible.js from above then I am getting a strange behavior. When the fieldset is open and I clik on the legend, it closes, reopens and then closes again. When I click on the closed fieldset it opens, closes and then reopens. Have you ever encountered this behavior? any ideas? Is the link to the collapsible.js file above pointing to the same file used in the demo?
Thank you,
Tony

PeterSmith's picture
Jun 28, 2011
4:07 am
PeterSmith

You published a really important information! It really helped me in my work! custom writing

jp2symposium.org's picture
Dec 14, 2013
4:55 pm
jp2symposium.org

“Reply to comment | Michael Irwin - Web Developer” was a fantastic blog
post. If merely there were even more web blogs just like this excellent one
in the actual cyberspace. Well, many thanks for ur precious time, Melina

kim's picture
Mar 13, 2013
11:48 am
kim

It was great to land on this blog post and to read such amazing stuff. Your blog is full of authentic and highly-researched information that is worth reading. I will surely recommend your blog to my fellows!
download youtube videos

best ways to make money's picture
Nov 4, 2013
6:32 am
best ways to make money

When I initially commented I clicked the "Notify me when new comments are added"
checkbox and now each time a comment is addedd I gett four e-mails with the same comment.

Is there anny waay you can rmove people from that service?
Cheers!

mikesir87's picture
Nov 5, 2009
6:41 pm
mikesir87

@Tony I have never seen this happen before, and I've used it on several of my sites. The collapsible.js file has the same source code as the one in the demo. Are you sure you're only including the js file once? If you have it more than once, it could be triggering the click event a few times. What browser are you experiencing this in?

Anthony's picture
Nov 6, 2009
5:13 pm
Anthony

Hi Michael,
I love your collapsible fieldsets. I have some that I wish to be initially closed upon pageload. Is this possible? Could you show how to implement this?
Thank you so much!
--Mike

empower network's picture
Nov 20, 2013
7:09 am
empower network

As the adxmin of this site is working, no uncertainty very soon it will be well-known,
due to its quality contents.

Anthony's picture
Nov 6, 2009
5:15 pm
Anthony

hi Michael,
Yes, I corrected that issue. I had somehow added the function three times to each fieldset. Doh! I'm not sure how but I have corrected it now and it works beautifully!
Is it possible to have the fieldset display closed initially?
Thank you,
Mike Anthony

mikesir87's picture
Nov 6, 2009
8:07 pm
mikesir87

Anthony,
I've made a revised version, and posted it as another attachment. It's the file labeled v2. At the end of the tutorial, I posted a little update on how to use it. The demo has also been updated to show this. If you want, I can extend this tutorial (probably make another one) that explains how I added the ability for options. Just let me know!
Thanks!

Alex B's picture
Apr 20, 2011
9:59 am
Alex B

Thanks for awesome tutorials about jQuery plugin - very useful for me! Nice stuff for my essay papers as practice in college.

makyaj yapma's picture
Nov 21, 2009
4:29 am
makyaj yapma

Thanks for this plug-in

Ella Harrow's picture
Nov 23, 2009
1:40 pm
Ella Harrow

Thanks i was looking for this for my site.

emichan's picture
Nov 23, 2009
3:29 pm
emichan

Hi, thanks for posting this. Just a quick suggestion. Instead of

$(this).parent().children().filter("p,img,table,ul,div, /
span,h1,h2,h3,h4,h5").toggle("slow");

why not use

$(this).parent().children().not("label").toggle("slow");

?

It will save having to anticipate all of the possible tags one could put inside a fieldset.

HTH, Emi

mikesir87's picture
Nov 23, 2009
3:33 pm
mikesir87

Great suggestion! I'll update the scripts. However, I'll change it to $(this).parent().children().not('legend') Thanks for the tip though! :-)

emichan's picture
Dec 6, 2009
3:37 pm
emichan

Yes, haha, I meant legend - not label. :)

Luis Monroy's picture
Dec 2, 2009
12:12 pm
Luis Monroy

This is great information. Thanks so much for sharing. Its really gonna help me out!

spoetnik's picture
Jan 31, 2010
3:36 pm
spoetnik

Great plugin. Got it working, but found one glitch.
When i would like to have an easyslider (http://cssglobe.com/post/5780/easy-slider-17-numeric-navigation-jquery-s...) in a default collapsed fieldset, the slider stays 'display:none' This doesn't get update by the Collapsible Fieldset plugin.
Any suggestions?

mikesir87's picture
Jan 31, 2010
4:02 pm
mikesir87

Do you have a demo URL in which I can check out?

Lord Matt's picture
Feb 1, 2010
12:15 pm
Lord Matt

I was able to get the initiated as closed to work by changing line 35 to

obj.children().not('legend').css('display', 'none');

As it stood it refused to start hidden.

However mixed text (not in anything else) images and form elements all seemed to become block elements or something including the a element which appeared to take up 100% of width and as you can imagine this looked messy.

The same thing happened while the fieldset was hiding the layout would deform.

I don't have a demo (actually I do but it is tucked behind a whole heap of security and is under development).

In the end I tired of ugly forms and removed everything so I could focus on getting everything else working. I'd love to have the time to get to the bottom of what was going on though.

mikesir87's picture
Feb 1, 2010
12:42 pm
mikesir87

Ahhh... I see. You are correct. I recently made the change on line 26, but didn't do it where you noticed. I've updated the script here, as well as the jQuery plugin repository.

For it to work correctly though, you will need to have some sort of wrapping element around it all (whether a div, span, p, etc.). Plain text will still appear (if not wrapped in anything), and I'm not too sure of a way around that (unless it creates an entirely new fieldset and legend, but that seems unnecessary). Let me know if you think of anything.

Vamshi's picture
Mar 2, 2010
2:03 pm
Vamshi

First of all Great Plugin! and thanks for sharing it!

I found a problem with this plugin,let me explain it as follows:

What if you have multiple field sets in one fieldset .

Parent1
Child1
Child2
Child3

When I collapse/un-collapse the child the parent collapses.

How can I avoid that ? Any thoughts

mikesir87's picture
Mar 2, 2010
2:38 pm
mikesir87

@Vamshi - nice catch! I've posted an updated version of the plugin, which should resolve the issue. Let me know if it works. It's version *.2

Vamshi's picture
Mar 3, 2010
2:20 pm
Vamshi

Awesome ! It works Gr8!

But when i collapse and un-collapse a fieldset the fields in it become distorted, and when i refresh it they will become normal.

Do you know what is causing it ?

mikesir87's picture
Mar 3, 2010
2:26 pm
mikesir87

What browser are you using? Do you have a demo or any screenshots?

Vamshi's picture
Mar 3, 2010
3:15 pm
Vamshi

When you collapse it the table inside the fieldset becomes:

When you un-collapse it the table inside the fieldset becomes:

I think that "block" thing is causing the problem

Vamshi's picture
Mar 3, 2010
3:17 pm
Vamshi

I am using Firefox , it works in IE 8 though

mikesir87's picture
Mar 3, 2010
4:09 pm
mikesir87

Well, the style="block" comes from jQuery itself because it is being shown again. I'm not too sure how to resolve this issue, as this is built-in into jQuery. There appear to be other people that are wondering this, looking at the API page for slideDown (http://api.jquery.com/slideDown/).

Peterborough Housing's picture
Mar 20, 2010
1:27 pm
Peterborough Housing

Very Great Plugin i want to say thank you for sharing it!

Varun Vohra's picture
Mar 22, 2010
12:58 pm
Varun Vohra

Michael

Thank you a million mate. This saved me some much needed trouble coding my own jQuery to do something similar to multiple accordions on the same page. I owe you one :)

-Varun

mikesir87's picture
Mar 22, 2010
1:03 pm
mikesir87

Glad you enjoyed it! Let me know what site you're using it on, and I'll add it to my list! (I'm going to have a list up soon)

Anonymous's picture
May 21, 2010
4:40 pm
Anonymous

Simpler:

$(document).ready(function(){
	$("fieldset.collapsible legend").click(function() {
		$(this).parent().children().not("legend:first").slideToggle("fast");
	});
	$("fieldset.collapsible.collapsed legend").parent().children().not("legend:first").hide();
});

Christian Voigt's picture
May 25, 2010
3:02 pm
Christian Voigt

To gain control over both states you could use

$("fieldset.collapsible legend").click(function() {
$(this).parent().children().not("legend:first").slideToggle("fast");
$(this).parent().toggleClass('collapsed');
});
$("fieldset.collapsible.collapsed legend").parent().children().not("legend:first").hide();

Todd's picture
Jun 3, 2010
3:04 am
Todd

Hey Michael,
Great plugin! Thanks for creating it.

Only problem I had was that it didn't play nicely with other JS libraries when using jQuery. Mainly the jQuery.noConflict() support to use a different identifier other than '$' for jQuery.

The fix for this is easy. I just changed the plugin to use 'jQuery' instead of the '$' variable in the plugin itself.

Thanks again!

Todd

mikesir87's picture
Jun 3, 2010
6:11 am
mikesir87

Great catch! I haven't had to use noConflict too much, so thanks for letting me know!

I've posted an updated version both here and in the plugin repository.

Thanks!

Chris's picture
Jun 4, 2010
5:18 am
Chris

Could this be used to display a form? Sorry if this is obvious but im new to jQuery.

mikesir87's picture
Jun 4, 2010
6:05 am
mikesir87

Sure! This could be used in a form to better organize the materials. Feel free to send me some details of what you're thinking in my contact form, and I'll help you through it! :-)

stonefield's picture
Jun 25, 2010
5:44 am
stonefield

Thank you for the plugin.

Is there a way to change the cursor behaviour? I'd like to have a "hand" when hovering over "legend".

mikesir87's picture
Jun 25, 2010
6:04 am
mikesir87

There absolutely is a way to do that. Using CSS, you can use the :hover attribute. So, it would be something like this:


legend:hover {
cursor: pointer
}

You can view more options by going to this page: http://www.w3schools.com/CSS/pr_class_cursor.asp

Hope it helps!

stonefield's picture
Jun 28, 2010
9:56 am
stonefield

Thanks for your help mikesir87. I think I was a bit confused when I was solving the problem and wrote "cursor: hand". ;)

anantha's picture
Jul 2, 2010
3:41 pm
anantha

I have a fieldset with id and inside the fieldset it has legend
and div..I want to collapse the fieldset..when i click it has to open and when i close it has to close...but i am thinking the code has used legend for clickable place..since i don't have legend in my code...can i use this code? i am thinking to just change the legend to h2 or something like that...will it work...reply plz...thx

mikesir87's picture
Jul 11, 2010
12:09 am
mikesir87

@anantha,

Sorry for the slow response... but, I'm not sure I fully understand what it is that you are requesting. You say you have a fieldset with a legend and div, but then you don't have a legend in it. Not quite sure... Do you have a link to an example that I can help you out with?

Alex Tiley's picture
Sep 3, 2010
5:00 am
Alex Tiley

Thanks for publishing this plugin, it's exactly what I've been looking for!

One question though. I am running a number of fieldsets within one form, and I would like to make it so that working within one fieldset (i.e. clicking a box within one fieldset) would close the one above to save space. Do you have any rough idea on how this could be accomplished?

mikesir87's picture
Sep 3, 2010
7:09 am
mikesir87

I'm not 100% sure what it is that you're asking, but here's my two ideas you're asking, and you just let me know which is right.

1) You want it so when you open a fieldset, any opened ones close automatically.
2) You want a link within another fieldset (or anywhere really) that when you press it will close the previous fieldset.

Both are do-able, but just let me know what you're thinking!

Alex Tiley's picture
Sep 3, 2010
8:26 am
Alex Tiley

Thanks for your reply. I'll try and explain myself a bit better.

Let's say I have a form with two fieldset's. If I click a field in the second fieldset, I would like the first fieldset to automatically close to allow me extra room on the form for my second fieldset when I dynamically add new inputs within the fieldset.

I still want both fieldsets' to collapse when I click the legend, but I also want to make the first fieldset collapse once I click any field within the second.

Hopefully this makes it clearer for you.

minecraft inventory editor's picture
Mar 17, 2014
1:03 pm
minecraft inventory editor

Hi! І've bеeո folowing your wweblog fօr sоme time now and
finally got the bravery to go ahead and give you a sout out from
Huffman Texas! Jusst աanted to tell you keeƿ up the excellent wоrk!

www.zennoposter-mentalpower.com's picture
Feb 4, 2014
1:52 am
www.zennoposter-mentalpower.com

I every time spent my half an hour to read this web site's posts every day along with a mug of
coffee.

stantonh's picture
Nov 3, 2010
4:12 pm
stantonh

Excellent plugin! Is there a way to change (append) the legend when closed in the js?

dclaar's picture
Nov 5, 2010
5:06 pm
dclaar

I'm trying to add the ability to save the collapsed/non-collapsed state in a cookie, so that the page will come back the same. But I'm not having any luck. The problem I'm running into is that jQuery seems to be random about reporting classes. I have 3 fieldsets, and I added this function:


$(document).ready(function() {
$("legend.collapsible").click(function() {
alert(
$("legend").map(function() {
return $(this).attr('class')
}).get().join("+"))
})
})

Originally, it was going to do hasClass("collapsed"), but when it didn't work, I switched to this. If I click on the first two fieldsets, I get collapsible+collapsible+collapsible no matter what the actual state is.
Only when the last fieldset is collapsed will the alert show the collapsed class, and then only if one of the other fieldsets is collapsed, e.g "collapsible+collapsible+collapsible collapsed" when the 2nd is collapsed and the 3rd was previously collapsed.

I even tried putting it directly into your plugin, but got the same results.

Obviously, this isn't a problem with your plugin, but I was wondering if you had any thoughts, or maybe a better way to do this? (One that works would be better:-) )

Thanks,
Doug

dclaar's picture
Nov 5, 2010
7:20 pm
dclaar

I've found that I can make it work by hacking the collapsible function at an early point to use the function's object to get it's state--which requires reversing the sense of test, because it is before it mucks with the collapsed class--but this doesn't work from a separate click function, or even later in this function. Yuck.


***************
*** 20,25 ****
--- 20,36 ----
return this.each(function() {
var obj = jQuery(this);
obj.find("legend:first").addClass('collapsible').click(function() {
+
+ alert(
+ $("legend").map(function(index,de) {
+ if ($(de).parent().get(0)===obj.get(0)) {
+ return(!obj.hasClass('collapsed'));
+ } else {
+ return($(de).hasClass('collapsed'));
+ }
+ }).get().join("+")
+ )
+
if (obj.hasClass('collapsed'))
obj.removeClass('collapsed').addClass('collapsible');

***************

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
  • Syntax highlight code surrounded by the {syntaxhighlighter SPEC}...{/syntaxhighlighter} tags, where SPEC is a Syntaxhighlighter options string or "class="OPTIONS" title="the title".

More information about formatting options