Blog-Archiv

Sonntag, 3. April 2016

JS / CSS Tabcordion

This is a follow-up of my Blog about JS / CSS Tabs. It introduces a way how tabs could be displayed in an Accordion manner without changing the structure of HTML. The source code for tabs is re-used, HTML structure is the same, some JS is overridden, some CSS is added.

I called that UI-control Tabcordion. It was inspired by Transformer Tabs on the CSS-Tricks web site. The difference is that Tabcordion (1) is not responsive, more it tries to replace Accordion, and (2) pretends to be ergonomic - the tab-title does not "jump".
Here is an example:

Lorem ipsum dolor sit amet, qui meliore deserunt at. Percipitur intellegam appellantur cu vim, mei soluta complectitur id, partem reprimique ullamcorper in vim.

The menu-button on the right is visible when all other tab-bars are hidden. When you click the bar, all other tab-bars will show, pushing the currently showing content down. Clicking the bar once more will hide them again, pulling up the content. But when you click one of the other tab-bars, its content will replace the current content. Any tab-bar below the clicked one will disappear then, but none of those above (→ difference to Transformer Tabs).

The disadvantage of Tabcordion is that not all tabs are initially visible. There is a constructor parameter that can change this, but then it looks like tabs that have been arranged vertically.

This might not be a UI-control you want to use, but it shows how well-written JS source could be reused to show completely different results, doing just a few overrides, and adding some CSS.


Tabs Source Base


Click on tab-bar above to navigate to the source code base I'm going to extend now. It is packed in script and style tags, uncommented, ready for copy & paste onto your web page. Mind that style go to head, while script tags should be at end of the body.

For a description of that source go to my last Blog about Tabs.


Tabcordion Overrides


Here is the module outline I am going to implement now, in a script tag. It extends the given instantiated tabBase module (parameter) by setting it to the local that object, and then replacing functions on it. (The tabBase was called tabModule in my last Blog.)

  <script type="text/javascript">
    /**
     * Create a tabcordion.
     * @param initiallyExpanded when true, tabcordions will be initially expanded,
     *     else they will be collapsed and the menu icon will show on selected button.
     * @returns the object to call init() upon to find tabbed panes and tabcordions.
     */
    var tabcordion = function(tabBase, keyboard, initiallyExpanded)
    {
      initiallyExpanded = (initiallyExpanded === undefined) ? false : initiallyExpanded;
      
      var that = tabBase;
      
      var initializing = true;
      
      ....

      var superInit = that.init;
      
      /**
       * Builds tabbed panes found in given topElement (or current document).
       * Overrides must be done before calling this.
       * @param topElement optional, default is document.body,
       *     the top-element where to search for tabbed-panes.
       */
      that.init = function(topElement) {
        superInit(topElement);
        initializing = false;
      };
      
      return that;
      
    };

  </script>

The initiallyExpanded parameter defaults to false to make tab-buttons below the focused one initially invisible. Passing true would change that Tabcordion behavior.

The local initializing flag will be used to mark the initialization phase. The init() override sets it to false at end of its execution.


Application

Here is an example Tabcordion.

Following is a Tabcordion containing

  • text content on Tab One,
  • a nested Tabcordion on Tab Two,
  • and a nested tabbed pane on Tab Three.

You can see it in action on top of this page.

The only structural difference between tabbed pane and Tabcordion is the CSS class on the top-level div element. Thus you could easily turn any Tabcordion into a tabbed pane just by changing the CSS class from "tabcordion" to "tabbed-pane".

        <div class="tabcordion">
          
          <ul role="tablist" aria-expanded='true'><li
                id="tab-1" role="tab" aria-controls="tab-panel-1" aria-selected="true">Tab One</li><li
                id="tab-2" role="tab" aria-controls="tab-panel-2" aria-selected="false">Tab Two</li><li
                id="tab-3" role="tab" aria-controls="tab-panel-3" aria-selected="false">Tab Three</li><li>
          </ul>
          
          <div role="tabpanel" id="tab-panel-1" aria-labelledby="tab-1">
            <p>Lorem ipsum dolor sit amet, qui meliore deserunt at.</p>
          </div>
          
          <div role="tabpanel" id="tab-panel-2" aria-labelledby="tab-2">
            
            <div class="tabcordion">
            
              <ul role="tablist"><li
                    id="tab-2-1" role="tab" aria-controls="tab-panel-2-1" aria-selected="true">Tab Two One</li><li
                    id="tab-2-2" role="tab" aria-controls="tab-panel-2-2" aria-selected="false">Tab Two Two</li><li
                    id="tab-2-3" role="tab" aria-controls="tab-panel-2-3" aria-selected="false">Tab Two Three</li>
              </ul>
          
              <div role="tabpanel" id="tab-panel-2-1" aria-labelledby="tab-2-1">
                <p>At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. </p>
              </div>
              
              <div role="tabpanel" id="tab-panel-2-2" aria-labelledby="tab-2-2">
                <p>Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu.</p>
              </div>
              
              <div role="tabpanel" id="tab-panel-2-3" aria-labelledby="tab-2-3">
                <p>At atqui choro theophrastus sit, ne erroribus vulputate vis, eam et antiopam scripserit. </p>
              </div>
              
            </div>
            
          </div>
          
          <div role="tabpanel" id="tab-panel-3" aria-labelledby="tab-3">
            
            <div class="tabbed-pane">
              <ul role="tablist"><li
                    id="tab-3-1" role="tab" aria-controls="tab-panel-3-1" aria-selected="true">Tab Three One</li><li
                    id="tab-3-2" role="tab" aria-controls="tab-panel-3-2" aria-selected="false">Tab Three Two</li><li>
              </ul>
          
              <div role="tabpanel" id="tab-panel-3-1" aria-labelledby="tab-3-1">
                <p>Lorem ipsum dolor sit amet, qui meliore deserunt at.</p>
              </div>
              
              <div role="tabpanel" id="tab-panel-3-2" aria-labelledby="tab-3-2">
                <p>Nec an stet decore honestatis, omittam maiestatis ei quo, eripuit facilis recusabo ius cu.</p>
              </div>
              
            </div>
        
          </div>
          
        </div>
        
  </div>

Summary

Tabs with WAI-ARIA are a little painful. You always have to provide ids and id-references for aria-controls and aria-labelled-by. Moreover the HTML structure, as proposed by WAI-ARIA, makes it hard to switch between Tabbed-Pane and Accordion without restructuring the HTML, because of the <ul role="tablist"> on top, containing all tab-buttons. For an Accordion, the tab-button would have to be directly above its tab-panel.

In a future Blog I will try to describe how we can organize Tabbed-Panes and Accordions transparently, without having to restructure the HTML. Why don't we want to restructure HTML, for example using JavaScript? Because CSS hardcodes the HTML structure sometimes, and CSS is often written without knowledge about the JS working in the page.




Keine Kommentare: