Menu icon Foundation
Accordion markup isn't great

Hey folks! I'm messing about with the new-style accordions and I must say I think the sample code is a bit of a worry. For my mind, the proposed markup is far too tied to a specific semantic HTML construct, which doesn't make a lot of sense to me for a general-purpose UI widget.

Secondly, it's not terribly good HTML - a definition list composed purely of DD elements and nested content? Why even use a DL in the first place if you're not going to leverage the interplay of the DT and DDs?

I have attempted to create the accordion with generic divs rather than DDs, but to no avail - the CSS is scoped to DDs. I think this is a bad move, overall.

accordioncss

Hey folks! I'm messing about with the new-style accordions and I must say I think the sample code is a bit of a worry. For my mind, the proposed markup is far too tied to a specific semantic HTML construct, which doesn't make a lot of sense to me for a general-purpose UI widget.

Secondly, it's not terribly good HTML - a definition list composed purely of DD elements and nested content? Why even use a DL in the first place if you're not going to leverage the interplay of the DT and DDs?

I have attempted to create the accordion with generic divs rather than DDs, but to no avail - the CSS is scoped to DDs. I think this is a bad move, overall.

Nick Caldwell over 5 years ago

OK, I honestly did add line breaks for paragraph breaks.

Kelicia Samuelson over 5 years ago

I absolutely totally agree. Using this markup seems like a big step backward. Using the sections markup seemed to suit the purpose much better. I don't see what value using this markup has over using sections or divs.

Peter Gibb over 5 years ago

Really surprised and disappointed to see how the accordion component is marked up. It fails W3C HTML validation which really makes it unusable - if we're willing to deploy markup like this we might as well go back to using FrontPage.

Can Zurb not offer some valid markup which still binds into functionality of the component?

Asif about 5 years ago

I'm surprised that this is not fixed yet. This does not validate with W3C HTML validation. I had to add in empty dt tags just above the dd tags just for the sake of HTML validation, but I'm not happy doing this.

<dt><dt>
<dd>
<div class="content">
content
 </div>

</dd>

Joseph Purcell about 5 years ago

In addition to validation, the constraints of the structure dd > .content and dd > a don't allow flexibility both in what elements you use and in the structure of those elements. In my opinion, it would be ideal if the accordion JavaScript helper could be used aside from the accordion HTML widget. For example, imagine if the JavaScript widget only required:

  • a parent element denoted by data-accordion
  • a trigger denoted by data-target="{selector}"
  • a container that opens and closes and matches the {selector} of a trigger

Example 1: You could have a section of articles (say, comments or excerpts) that are an accordion:

<section data-accordion>
  <article>
    <header>
      <h1 data-target="#accordion1">Accordion 1</h1>
    </header>
    <div id="accordion1">
      <p>Hello, you can close or open this.</p>
    </div>
  </article>
  <article>
    <header>
      <h1 data-target="#accordion2">Accordion 2</h1>
    </header>
    <div id="accordion2">
      <p>Hello, you can close or open this.</p>
    </div>
  </article>
</section>

Example 2: You could have a lengthy article with each section as an accordion.

<article data-accordion>
  <header>
    <h1>This is an article</h1>
    <nav>
      <h1>Table of Contents</h1>
      <ul>
        <li><a href="#section1" data-target="#section1">Section 1</a></li>
        <li><a href="#section2" data-target="#section2">Section 2</a></li>
      </ul>
    </nav>
  </header>
  <section>
    <h1>Section 1</h1>
    <div id="section1">
      <p>You can open or close this using the table of contents.</p>
    </div>
  </section>
  <section>
    <h1>Section 2</h1>
    <div id="section2">
      <p>You can open or close this using the table of contents.</p>
    </div>
  </section>
</article>

Example 3: You could still have your HTML widget with default styling.

<dl class="accordion" data-accordion>
  <dd>
    <a href="#panel1" data-target="#panel1">Accordion 1</a>
    <div id="panel1" class="content">You can open or close this.</div>
  </dd>
  <dd>
    <a href="#panel2" data-target="#panel2">Accordion 2</a>
    <div id="panel2" class="content">You can open or close this.</div>
  </dd>
</dl>

These are just thoughts that may be bogus or useful.

Rafi Benkual about 5 years ago

@Joseph, Interesting note. Aside from validation, it is interesting to see what the issue with this markup is.
On the validation front, here is how we feel about it: http://zurb.com/article/1260/we-ve-moved-beyond-code-validators

Our lead designer on Foundation commented about this in reference to tabs:
"We found in practice the sections element was great for quick prototyping and an unholy disaster for actual production work (the enforced styling was way too rigid). Our belief at this juncture is that the tabs / accordion elements combined with either visibility classes or Interchange provide a more robust albeit wordier solution."

"I am interested to hear about other ideas for this – it was not an easy decision. As far as tabs are concerned they should be built from UL not DL elements, and we'll be adjusting that in the near future (for a number of elements, actually, by removing the specific tag dependency)."

https://github.com/zurb/foundation/issues/4308

James Stone about 5 years ago

I think after reading Rafi's background post on the reasoning and looking at how it has been clarified in html5 vs. html4 I am happy with the way that it has been used. Here is some more background information if anyone is interested:

http://html5doctor.com/the-dl-element/

I think especially looking at the glossary example, that this is how the accordion is working. A term, the title for the accordion tab as well as its definition as the body of the accordion element.

I see people mention this a lot with the accordion. I think a big part of it is that definition lists are a bit more on the obscure side and many people might not be that familiar with them or the syntax. Maybe a short line in the docs might clear this up for users that are new to the syntax?

Nick Caldwell about 5 years ago

Well, I'm actually very familiar with definition lists and I still think using them in an accordion is dodgy. What do you gain by using that structure and ONLY using the DD and not the DT?

The bigger point is that the semantics of the HTML elements are debatable. For instance, there's an argument that SECTION should only be used for general divisions like book chapters, not UI constructs. DIVs are frequently the correct choice when you don't want difficult semantic baggage messing up your document outline (which many screen readers use to help a blind user make sense of a document).

Why not just tie the functionality of UI constructs such as accordions to the class names? That way the HTML author gets to decide the validity of the markup they use themselves.

Asif about 5 years ago

 What do you gain by using that structure and ONLY using the DD and not the DT?

I agree with nick here, my 2 cents is that, I agree that a lot of thought has gone into selection of tags to use, be it UL, DD, sections, articles or whatever, but when you do select a structure then we at least have to make sure that their usage is right, like nick said, using DD is fine but not using the required DT is a problem.

as for Zurb's article on moving beyond code validators, I agree to an extent, but then again we need to at least make proper use of whatever we are using. Zurb's foundation is a framework and will be used in building a lot of products in different applications, Sometimes these products need to be compliant. like for instance we are creating a WordPress theme, and any theme that is developed needs to be HTML validated. Now if the framework's components are not compliant with W3C standards at least with HTML then there is no point in using the framework to build this product, but luckily its just a couple of components that are causing these issues and we could get around them by adding dummy DTs or likewise, but I think with respect to the accordions as nick pointed out, if we are using DDs then DTs need to be present in there. I mean these are simple required rules that need to be taken care.

Joel Kinzel almost 5 years ago

Validation is only part of the picture. What about those who are using screen readers or other assistive technologies? They read the HTML markup, so I'd be curious to know how this impacts them. My gut is telling me they might choke on a DL without a DT/DD relationship. That is a big problem for those who need 508 compliance (and realistically, even if it isn't required of your organization, you should be striving for it anyway).

PS - The changes to the code to make everything kosher really aren't that significant. I just made all of them in my own project in about 30 minutes. I now have fully functional tabs and accordions which are using (IMO) more proper markup for screen readers. Now to add aria data attributes for even better accessibility...

Andrew J. Holden almost 5 years ago

Bit late to the game on this, but I'd echo Nick's sentiments. If we could remove the dependency on certain markup elements, or at least add a few more valid element options - it would be very helpful to those of us who are working on complex state-driven applications :)

  • Thanks!

Drsii almost 5 years ago

Going to jump in here as well. I think the entire accordion concept should take a step back, view the entire requirement of collapsing and expanding elements. Remove the dependency on html elements. + 1

Bob Sawyer over 4 years ago

Just my $0.02 ... If you're GOING to use a DL, seems to me that the DT would be the tab and the DD would contain the content -- right? So from this:

<dl class="accordion" data-accordion>
  <dd class="accordion-navigation">
    <a href="#panel1">This is panel 1</a>
    <div id="panel1" class="content">
      <p>Lorem ipsum dolor sit blah blah blah</p>
    </div>
  </dd>
  <dd class="accordion-navigation">
    <a href="#panel2">This is panel 2</a>
    <div id="panel2" class="content">
      <p>Lorem ipsum again?</p>
    </div>
  </dd>
</dl>

To this:

<dl class="accordion" data-accordion>
  <dt class="accordion-navigation">
    <a href="#panel1">This is panel 1</a>
  </dt>
  <dd id="panel1" class="accordion-content">
    <p>Lorem ipsum dolor sit blah blah blah</p>
  </dd>
  <dt class="accordion-navigation">
    <a href="#panel2">This is panel 2</a>
  </dt>
  <dd id="panel2" class="accordion-navigation">
    <p>Lorem ipsum again?</p>
  </dd>
</dl>

makes a little more sense, from a semantic POV, and it validates.

Wayne Theisinger over 4 years ago

Also there isn't a great deal of point allowing users to change the class names using mixins:

.your-accordion-class  {
  @include accordion-container;

  .your-accordion-navigation-class  {
    @include accordion-navigation;
  }

  .your-accordion-content-class  {
    @include accordion-content;
  }
}

Unless your javascript handles it:

Below is the edited javascript to enable the changing of classes in settings:

 ;(function ($, window, document, undefined) {
  'use strict';

  Foundation.libs.accordion = {
    name : 'accordion',

    version : '5.4.7',

    settings : {
      accordion_class: 'accordion',
      navigation_class: 'accordion-navigation',
      content_class: 'content',
      active_class: 'active',
      multi_expand: false,
      toggleable: true,
      callback : function () {}
    },

    init : function (scope, method, options) {
      this.bindings(method, options);
    },

    events : function () {
      var self = this;
      var S = this.S;
      S(this.scope)
      .off('.fndtn.accordion')
      .on('click.fndtn.accordion', '[' + this.attr_name() + '] > .' + self.settings.navigation_class + ' > a', function (e) {
        var accordion = S(this).closest('[' + self.attr_name() + ']'),
            groupSelector = self.attr_name() + '=' + accordion.attr(self.attr_name()),
            settings = accordion.data(self.attr_name(true) + '-init') || self.settings,
            target = S('#' + this.href.split('#')[1]),
            aunts = $('> .'+settings.navigation_class, accordion),
            siblings = aunts.children('.'+settings.content_class),
            active_content = siblings.filter('.' + settings.active_class);

        e.preventDefault();

        if (accordion.attr(self.attr_name())) {
          siblings = siblings.add('[' + groupSelector + '] .' + self.settings.navigation_class + ' > .' + self.settings.content_class);
          aunts = aunts.add('[' + groupSelector + '] .' + self.settings.navigation_class);
        }

        if (settings.toggleable && target.is(active_content)) {
          target.parent('.'+self.settings.navigation_class).toggleClass(settings.active_class, false);
          target.toggleClass(settings.active_class, false);
          settings.callback(target);
          target.triggerHandler('toggled', [accordion]);
          accordion.triggerHandler('toggled', [target]);
          return;
        }

        if (!settings.multi_expand) {
          siblings.removeClass(settings.active_class);
          aunts.removeClass(settings.active_class);
        }

        target.addClass(settings.active_class).parent().addClass(settings.active_class);
        settings.callback(target);
        target.triggerHandler('toggled', [accordion]);
        accordion.triggerHandler('toggled', [target]);
      });
    },

    off : function () {},

    reflow : function () {}
  };
}(jQuery, window, window.document));

Which can be set with:

 jQuery(document).foundation({
    accordion: {
    accordion_class: 'your-accordion-class',
    navigation_class: 'your-accordion-navigation-class',
    content_class: 'your-content-class',
    active_class: 'active',
    // allow multiple accordion panels to be active at the same time
    multi_expand: false,
    // allow accordion panels to be closed by clicking on their headers
    // setting to false only closes accordion panels when another is opened
    toggleable: true
    }
});

The difference being the addition of navigation_class and the adding content_class into the javascript where it had been missed.