Nested Accordion

A simple, nestable accordion with some examples of nesting levels and a media query.

Nested Accordion

View demo Download source

A simple accordion that allows for a nested structure. The style comes with some examples of how to style three levels and how to add a media query for decreasing the size on smaller screens. Clicking a trigger element will open the content.

The HTML

<ul id="cbp-ntaccordion" class="cbp-ntaccordion">
	<li>
		<h3 class="cbp-nttrigger">Oat cake tootsie roll</h3>
		<div class="cbp-ntcontent">
			<p><!-- ... --></p>
			<ul class="cbp-ntsubaccordion">
				<li>
					<h4 class="cbp-nttrigger">Donut pastry</h4>
					<div class="cbp-ntcontent"><!-- ... --></div>
				</li>
				<li>
					<h4 class="cbp-nttrigger">Carrot cake</h4>
					<div class="cbp-ntcontent">
						<!-- ... -->
						<ul class="cbp-ntsubaccordion">
							<li>
								<h5 class="cbp-nttrigger">Donut pastry</h5>
								<div class="cbp-ntcontent"><!-- ... --></div>
							</li>
							<li><!-- ... --></li>
							<li><!-- ... --></li>
						</ul>
					</div>
				</li>
				<li>
					<h4 class="cbp-nttrigger">Tootsie roll marshmallow</h4>
					<div class="cbp-ntcontent">
						<!-- ... -->
					</div>
				</li>
			</ul>
		</div>
	</li>
	<li><!-- ... --></li>
	<li><!-- ... --></li>
	<li><!-- ... --></li>
</ul>

The CSS

/* Icon font for arrow icons */
@font-face {
	font-family: 'icomoon';
	src:url('../fonts/icomoon_arrows/icomoon.eot');
	src:url('../fonts/icomoon_arrows/icomoon.eot?#iefix') format('embedded-opentype'),
		url('../fonts/icomoon_arrows/icomoon.woff') format('woff'),
		url('../fonts/icomoon_arrows/icomoon.ttf') format('truetype'),
		url('../fonts/icomoon_arrows/icomoon.svg#icomoon') format('svg');
	font-weight: normal;
	font-style: normal;
} /* Iconfont by Icomoon http://icomoon.io/ */


/* Accordion style */
.cbp-ntaccordion {
	list-style: none;
	margin: 0;
	padding: 0;
}

.cbp-ntsubaccordion {
	list-style: none;
}

.cbp-ntaccordion .cbp-nttrigger {
	cursor: pointer;
} 

.cbp-ntaccordion h3 {
	margin: 0 0 0.3em;
	padding: 1em 0 0.5em;
	border-bottom: 1px solid #ddd;
	font-size: 2.75em;
	font-weight: 300;
}

.cbp-ntaccordion h4 {
	font-size: 1.2em;
	text-transform: uppercase;
	letter-spacing: 0.4em;
	padding: 0.5em 0 0.5em;
	margin: 0 0 0.5em;
}

.cbp-ntaccordion h5 {
	font-size: 1.2em;
	color: #aaa;
	padding: 0.5em 0 0.5em;
	margin: 0 0 0.5em;
}

.cbp-ntaccordion .cbp-ntcontent p {
	color: #888;
	font-size: 1.25em;
	font-weight: 300;
	line-height: 1.5;
	padding: 0.2em 0 1.5em;
	margin: 0;
}

/* Arrow icons */
.cbp-ntaccordion > li > .cbp-nttrigger:before,
.cbp-ntsubaccordion > li > .cbp-nttrigger:before {
	font-family: 'icomoon';
	speak: none;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	color: #ddd;
	margin-right: 0.5em;
	-webkit-font-smoothing: antialiased;
}

.cbp-ntaccordion > li > .cbp-nttrigger:before {
	font-size: 75%;
}

.cbp-ntaccordion > li > .cbp-nttrigger:before {
	content: "\36";
}
.cbp-ntaccordion > li > .cbp-nttrigger:hover:before {
	content: "\35";
	color: inherit;
}
.cbp-ntaccordion > li.cbp-ntopen > .cbp-nttrigger:before,
.no-js .cbp-ntaccordion > li > .cbp-nttrigger:before {
	content: "\34";
	color: inherit;
}

.cbp-ntsubaccordion > li > .cbp-nttrigger:before {
	content: "\32";
}
.cbp-ntsubaccordion > li > .cbp-nttrigger:hover:before {
	content: "\33";
	color: inherit;
}
.cbp-ntsubaccordion > li.cbp-ntopen > .cbp-nttrigger:before,
.no-js .cbp-ntsubaccordion > li > .cbp-nttrigger:before {
	content: "\31";
	color: inherit;
}

/* Initial height is zero */
.cbp-ntaccordion .cbp-ntcontent {
	height: 0;
	overflow: hidden;
}

/* When open, set height to auto */
.cbp-ntaccordion .cbp-ntopen > .cbp-ntcontent,
.cbp-ntsubaccordion .cbp-ntopen > .cbp-ntcontent,
.no-js .cbp-ntaccordion .cbp-ntcontent {
	height: auto;
}

/* Example for media query */
@media screen and (max-width: 32em) { 

	.cbp-ntaccordion {
		font-size: 70%;
	}

}

The JavaScript

/**
 * jquery.cbpNTAccordion.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
;( function( $, window, undefined ) {

	'use strict';

	// global
	var $body = $( 'html, body' );

	$.CBPNTAccordion = function( options, element ) {
		this.$el = $( element );
		this._init( options );
	};

	// the options
	$.CBPNTAccordion.defaults = {};

	$.CBPNTAccordion.prototype = {
		_init : function( options ) {
			// options
			this.options = $.extend( true, {}, $.CBPNTAccordion.defaults, options );
			// cache some elements and initialize some variables
			this._config();
			// initialize/bind the events
			this._initEvents();
		},
		_config : function() {

			// the clickable items
			this.$items = this.$el.find( '.cbp-nttrigger' );

		},
		_initEvents : function() {
			
			this.$items.on( 'click.cbpNTAccordion', function() {
				var $listItem = $( this ).parent();
				if( $listItem.hasClass( 'cbp-ntopen' ) ) {
					$listItem.removeClass( 'cbp-ntopen' );
				}
				else {
					$listItem.addClass( 'cbp-ntopen' );
					$body.scrollTop( $listItem.offset().top );
				}
			} );

		},
		destroy : function() {
			this.$items.off( '.cbpNTAccordion' ).parent().removeClass( 'cbp-ntopen' );
		}
	};

	var logError = function( message ) {
		if ( window.console ) {
			window.console.error( message );
		}
	};

	$.fn.cbpNTAccordion = function( options ) {
		if ( typeof options === 'string' ) {
			var args = Array.prototype.slice.call( arguments, 1 );
			this.each(function() {
				var instance = $.data( this, 'cbpNTAccordion' );
				if ( !instance ) {
					logError( "cannot call methods on cbpNTAccordion prior to initialization; " +
					"attempted to call method '" + options + "'" );
					return;
				}
				if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
					logError( "no such method '" + options + "' for cbpNTAccordion instance" );
					return;
				}
				instance[ options ].apply( instance, args );
			});
		} 
		else {
			this.each(function() {	
				var instance = $.data( this, 'cbpNTAccordion' );
				if ( instance ) {
					instance._init();
				}
				else {
					instance = $.data( this, 'cbpNTAccordion', new $.CBPNTAccordion( options, this ) );
				}
			});
		}
		return this;
	};

} )( jQuery, window );

View demo Download source

Previous:
Next:

Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by

Website: http://www.codrops.com

Related Articles

Receive our bi-weekly Collective or official newsletter right in your inbox.

Which newsletter would you like to receive?

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 37

Comments are closed.
  1. 1

    I would love to figure out how to stop this from jumping to the top also. I have a fixed header and this is creating problems for me.

  2. 3

    Hi there,

    Love this accordion, but I was wondering if there’s a way to call a certain trigger. EG, have a list of 1 2 3 4 as the main content of the page, but then I would also like a side bar with 1 2 3 4 that will call it’s respective drop down in the main content.

    I have played about, but I’m not so hot with JS, so just wondering if anybody knew of a method?

    Thanks in advance, and thanks for sharing Mary!

    • 4

      Also trying to figure this out.

      Has anyone found a solution to this?

      Thanks!

  3. 5

    Hi!

    THis is a really good accordion. I was wondering if there is a way to close the all the rest of the accordeon tabs when theres one opened.

    Thanks!

  4. 6

    I wan to slow down the opening using “ease”. The bit of java script that goes at the bottom of the page does not allow this. I do not want to limit the size of the accordion which if set, does allow a css ease. I have generated content that does not fit into a one size fits all height.

    Would it be possible to add in the lower js a way to have options and the accordions to slowly ease open?

    Thank you Dane

  5. 9

    For those having issues with user provided code, be sure that when you copy and paste the code from a comment that you change the smart quotes ( ‘ ’ ) into straight single quotes. The comments automatically convert straight single quotes into smart quotes which is why your code isn’t working.

Comments are closed.