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:

Mary Lou (Manoela Ilic) 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://tympanus.net/

Related Articles

Feedback 33

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!

Comments are closed.