Using Section Elements With Accordions

Using section elements instead of div elements for the jQuery UI accordion widget.

by Adam Boduch

HTML

<!-- This markup uses the <section> element -->
<h1 class="ui-widget">Using section elements</h1>
<a href="#" class="toggle ui-widget">Create Accordion</a>
<div>
    <section>
        <h3>Section 1</h3>
        <p>Section 1 content</p>
    </section>
    <section>
        <h3>Section 2</h3>
        <p>Section 2 content</p>
    </section>
    <section>
        <h3>Section 3</h3>
        <p>Section 3 content</p>
        <ul>
            <li>List item one</li>
            <li>List item two</li>
            <li>List item three</li>
        </ul>
    </section>
</div>

<!-- This markup uses the <div> element, the accordion default -->
<h1 class="ui-widget">Using div elements (the default)</h1>
<a href="#" class="toggle ui-widget">Create Accordion</a>
<div>
    <h3>Section 1</h3>
    <div>
        <p>Section 1 content</p>
    </div>
    <h3>Section 2</h3>
    <div>
        <p>Section 2 content</p>
    </div>
    <h3>Section 3</h3>
    <div>
        <p>Section 3 content</p>
        <ul>
            <li>List item one</li>
            <li>List item two</li>
            <li>List item three</li>
        </ul>
    </div>
</div>

CSS

body {
    font-size: 0.8em;
}

h1 {
    border-bottom: solid 1px;
}

JavaScript

(function( $ ) {
    
    // We need to extend the accordion widget so that it understands
    // the <section> element.
    $.widget( "ui.accordion", $.ui.accordion, {

        // Called when the accodion instance is created.
        _create: function() {

            // Check if we have any section elements. Otherwise, execute the
            // default behavior and exit.
            if ( this.element.find( "section" ).length === 0 ) {
                return this._super();
            }
            
            // The first child element of each section is the header.
            this.option( "header", "> section > :first-child" );
            
            // Wrap the remaining section content in a div that the accordion
            // expects to find.
            this.element.find( this.options.header ).each( function() {
                $( this ).siblings().wrapAll( "<div/>" );
            });
            
            // We're now ready to call the default constructor.
            this._super();
            
        },
        
        // Called when the accordion instance is destroyed.
        _destroy: function() {
            
            // If there's no section elements, we're free to just call the
            // default _destroy() and exit.
            if ( this.element.find( "section" ).length === 0 ) {
                return this._super();
            }
            
            // Unrap the div that was holding the section content.
            this.element.find( this.options.header ).each( function() {
                var $content = $( this ).next();
                $content.replaceWith( $content.children() );
            });
            
            // We can call on the regular destructor to finish off the cleanup.
            this._super();
            
        }
        
    });
    
    $(function() {
        // The toggle buttons create and destroy the two accordions. Notice
        // how we don't need to pass extra options to the constructor...