Demo of prependFoldingArrowIcon jQuery plug-in

Please note: This plug-in concentrates on drawing the SVG icon, which may even be animated with CSS transitions. The actual content-folding is not part of this plug-in. The following examples add some very simple folding with jQuery's slideDown() and slideUp() methods with a delay argument. These slideDown() and slideUp() mechanism actually needed some tricky CSS tweaks to really run smoothly (only applied in the »Foldable Sections« examples below), please refer to the source code of this page if interested.

Foldable list items

Defaults

Let's start the examples with the most common use-case: foldable sub-lists in list items.

For this example, we create a demo HTML list with the following markup:


<ul id="l1" class="folding-arrows">
    <li id="g1"><a href="#!">Test list item</a>
        <br>
        Second line
        <ul>
            <li>sub</li>
            <li>list</li>
        </ul>
    </li>
    
    <li id="g1b" class="showing">
        <a href="#!">Test list item</a>
        <br>
        Second line
        <ul class="folding-arrows">
            <li>sub<br>still sub</li>
            <li>list</li>
        </ul>
        
    </li>
</ul>

This is what it looks like – with the folding arrow icon plugin applied with default settings:

The examples above demonstrate the default shape of the folding arrow icon, being a closed triangle pointing to the right resp. down. The javascript to include them is quite simple:

$("#l1 > li, #l1 ul.folding-arrows > li").prependFoldingArrowIcon();

This JavaScript alone is not enough, since the inserted SVG is unstyled, so you need to add some CSS code to define the size and color theme:

This Library already comes with an included CSS file (jquery-folding-arrow-icon.css), which defines a default size for the images and the transition for rotating the arrow when the CSS class of the list item changes. Specifically for icons in unordered lists, it also contains rules which align list items without bullets and with this SVG image (inline inside the li's content) neatly with other normally bulleted list items (see first sub list with default list bullets and compare its alignment to the second sub list equipped with arrow icons).

But including that CSS file still isn't enough, since it does not define the actual look (colors and line with) of the graphic. That, you' still have to define on your own (otherwise it will default to a black triangle). This demo actually defines two different color settings for the first and the second list item:

#g1 .folding-arrow-icon path {
    stroke: none;
    fill: silver;
}

#g1b .folding-arrow-icon path {
    stroke: none;
    fill: #a00
}

Now, you just have to add the class "showing" to a list item if its icon should be transformed to a down-pointing arrow, removing the class transforms it back into a right-pointing arrow. Actually, in the example above, the second list item has been fitted with a "showing" class statically (see HTML markup shown above), which is why it's already unfolded upon page load, while the first is initially folded.

Please note that this jQuery plug-in does not hide or show the actual sub lists, but concentrates on just providing the animatable triangle icon. The actual folding has to bee implemented separately (though I'm planning to release a higher-level jQuery plug-in in the future, which will simplify showing or hiding sections and adding a class like showingto a switch element in order to display the folding state like – but not limited to – using this icon plug-in).

This example page uses the following JavaScript code (for the demo above as well as the following ones) in order to show and hide sub-lists:

$(function() {
    function openOrClose(jqr) {
        return jqr.toggleClass("showing").transformFoldingArrowIcon();
    }
    
    function openOrCloseLi(li) {
        openOrClose(li);
        if (li.is(".showing"))
            $("ul", li).slideDown(500);
        else
            $("ul", li).slideUp(500);
    }

    $("ul.folding-arrows > li > a, ul.folding-arrows > li > svg.folding-arrow-icon:not(.static)").click(function(){
        ev.preventDefault();
        openOrCloseLi($(this).parent());
    });
    $("ul.folding-arrows > li:not(.showing) > ul").hide();
});

Please note the calling of a further jQuery plug-in function provided by this library: transformFoldingArrowIcon(). As long as your page is viewed with a browser that supports transformations via CSS, this plug-in is not needed, since the loaded default CSS already defines the rotation transformation along with a CSS transition.

The click handler is only applied to those SVGs of class folding-arrow-icon which do not also have the class static. The latter is used by default to denote icons for static, not foldable list items. The shape of these icons might be a dash or disc (see examples for dash or disc presets further below) or some custom-designe other icons like a diamond, square etc.

Unfortunately, the Microsoft browsers (Edge and Internet Explorer) do not support CSS transformations for inline SVG, they require the transformations defined in tag attributes inside the SVG code. The transformFoldingArrowIcon() function adds or removes such a transformation attribute depending on the current state (whether the element has or has not the class "showing"). If called without parameters, the default transformation is used.

Please note: If both a transition attribute and a CSS transition are defined for the same SVG element, the CSS transition is used and the attribute is ignored.

Variations

Click a variation list item in order to view the description and code samples.

Bullets for static (non-foldable) list items

Foldable Sections

The plug-in isn't limited to creating list item bullets. To show just one alternative, the following examples will all use a heading (h2) to show or collapse a document section by clicking the heading.

The secions in these examples all have the following structure:

<h2 class="sec"><a href="#!">This is a section header</a></h2>
<div>
    <p>Section content. Note this is all wrapped in one single div in order to simplify
    collapsing or re-showing this content block.</p>
    <p>See JavaScript function openOrCloseSection() below, which will simply hide or show
    the first sibling after the heading, which is exactly this div.</p>
</div>

The whole heading should accept a mouse click event, but the link element (a) inside is to make sure that the section can also be toggled by keyboard users (accessibility!). See the registerClickHandler() function below, which registers one click handler at the heading itself, one on the link, and the latter has to prevent event bubbling so that the handler is not executed twice (once for clicking the link and a second time for clicking the heading)!

All of the section examples use some common JavaScript and CSS code. Note that the openOrCloseSection() function not only folds or unfolds one section, but also any other currently open section will be folded prior to unfolding a newly selected one. Of course this is only an example, but this behaviour is often found on the web.

function openOrClose(jqr) {
    return jqr.toggleClass("showing").transformFoldingArrowIcon();
}

function openOrCloseSection(h) {
    if (!h.is(".showing")) {
        //collapse currently open section(s):
        $("h2.sec.showing").each(function() {
            openOrCloseSection($(this));
        });
        openOrClose(h);
        h.next().slideDown500);
    } else {
        openOrClose(h);
        h.next().slideUp(500);
    }
}

function registerSectionClickHandler(section) {
    section.click(function() {
        openOrCloseSection(section)
    }).children("a").first().click(function(ev) {
        ev.preventDefault();
        ev.stopPropagation();
        openOrCloseSection(section);
    });
}

$(function(){
    $("h2.sec").each(function() {
        //Initially collapse all sections.
        //Do this dynamically by script in order to have all section opened and visible
        //in case JavaScript should be disabled in the browser.
        $(this).next().hide();
    }).setupFoldingArrowIconTransformation({
        //Global title common to all of the examples
        titleHidden: "open section"
    });
})
h2.sec {
    border: 1px solid silver;
    background-color: #eee;
    border-radius: 0.3em;
    padding: 0.2em;
    margin-top: 0;
}
h2.folding-arrow + div > :first-child {
    margin-top: 0;
}
h2.folding-arrow + div > :last-child {
    margin-bottom: 0;
}
h2.folding-arrow + div {
    margin-bottom: 2em;
}
/*
    Note: the margins above (no top margin of the h2 itself and no top margin
    for the first child in the hideable content resp no bottom margin for
    the content's last child are chosen in order to enable a smooth folding animation
    by jQuery's slideDown) and slideUp() methods. Margins in these places would cause "jumps"
    at the start and end of the animation, as the top margin of an element gets usually
    "merged" with the bottom margin of its next sibling, while during the animation they
    add up.
*/

Prepended arrow icon

This is a very simple example and uses the same function to prepend an icon as did the previous list item demos:

registerSectionClickHandler(
    $("#sec-prefix").prependFoldingArrowIcon({
        closePath: false
    }).setupFoldingArrowIconTransformation()
);

As with the list item examples, you still have to add CSS styles to define the looks of the generated SVG. Here, we'll define some styles which will not only be used for this example, but also for some more of the following demos:

h2.folding-arrow .folding-arrow-icon path {
    stroke: navy;
    stroke-width: 2;
    fill: none;
}

Appended arrow icon

A variation of the previous example, differing in the following aspects:

  1. Use of the plug-in function appendFoldingArrow() instead of prependFoldingArrow(), which, as its name suggests, inserts the SVG icon at the end of the heading element instead of at its beginning.
  2. Use of the preset arrow-up-down, which shows a down-pointing triangle for collapsed and an up-pointing triangle for unfolded sections and doesn't use a rotation transition, but a vertical mirroring transition to switch between them. (Of course you could override that by defining a 180° rotation, too.)
registerSectionClickHandler(
    $("#sec-postfix").appendFoldingArrowIcon({
        preset: "arrow-up-down",
        closePath: false
    }).setupFoldingArrowIconTransformation({
        preset: "arrow-up-down"
    })
);

No further CSS code needed: This example re-uses the CSS shown in the previous example for defining the looks of the arrow icon itself and the included jquery-folding-arrow-icon.css file's default rules for the transition defined by the preset.

Right-aligned arrow icon

Again, a variation of the previous example, mainly differing in the alignment of the icon via special CSS code. The following CSS is used for this and all other following section examples:

h2.sec.al-right .folding-arrow-icon {
    float: right;
    width: 1em;
    height: 1em;
    margin-top: 0.1em;
}

The JavaScript code is mainly the same, only one variation has been made: Since the Icon is independently aligned, the separator property gets redefined in order not to append an unnecessary space character to the heading text (even though that would not actually be visible):

registerSectionClickHandler(
    $("#sec-al-right").appendFoldingArrowIcon({
        preset: "arrow-up-down",
        closePath: false,
        separator: ""
    }).setupFoldingArrowIconTransformation({
        preset: "arrow-up-down"
    })
);

Combining chevron with circle

This example is a variation of the previous one, simply adding a circle to the "arrow-up-down" preset's icon.

In this case, the circle should be filled and should be prepended to the arrow icon, i.e. be placed behind the latter. Since the background circle is filled with a dark (blue) color, the foreground icon is formatted uses a white stroke.

For more explanations on the code, please refer to the previous list item examples!

var arrowUpDownInCircle = $.fn.prependFoldingArrowIcon.copyOfPreset("arrow-up-down")
    .prependToGraph("circle", {"cx": "0", "cy": "0", "r": "10"})
    .prop("viewboxRadius", 10)
    .prop("viewboxMargin", 0)
    .prop("closePath", false);

$("#sec-al-right-circle1, #sec-al-right-circle2").prependFoldingArrowIcon({
    preset: arrowUpDownInCircle,
    separator: ""
})
registerSectionClickHandler(
    $("#sec-al-right-circle1").setupFoldingArrowIconTransformation({
        preset: arrowUpDownInCircle
    })
);
#sec-al-right-circle1 .folding-arrow-icon circle {
    stroke: none;
    fill: #007;
}
#sec-al-right-circle1 .folding-arrow-icon path {
    stroke: white;
}

Animating only part of the SVG

In the previous example, the whole graphic, i.e. the circle with the white chevron in it, gets flipped vertically. In the end result, only the arrow has changed its direction, while the circle still looks the same (naturally). Yet, during the transition, the whole circle gets shrunken and expanded again. This may feel a litte obtrusive, so this example provides a more discreet transition.

It simply differs from the previous example only in the one aspect, that instead of the whole icon (or, to be more precise, the group inside the SVG image which consists of two shapes, the circle and the array) now only the arrow shape is to be flipped, while the circle rests untouched.

The main Javascript code and CSS styles are exactly the same as in the example above (except, of course, that a different section ID is selected). Here, we'll only show the code defining the different transformation and transition:

#sec-al-right-circle2 .folding-arrow-icon > g {
    transition: none;
    transform: none;
}
#sec-al-right-circle2 .folding-arrow-icon path {
    transition: transform 0.5s;
}
#sec-al-right-circle2.showing .folding-arrow-icon path {
    transform: scale(1, -1);
}

The first CSS rule overrides the default transition and tranformation for the group (g) inherited from the included CSS file. The other two rules define a transition for the path node and a transformation for the path node in case it is marked as showing. Keep in mind, the image inside the generated SVG contains one group element g with two childen: a circle and a path element, and we only want to transform the latter.

Since the end result looks the same as in the previous example, only the transitions (animations) differ, and the IE-/Edge fallback defined by setupFoldungArrowIconTransformation does not support transition, one might think at first glance, that nothing has to be changed here, the setup method could still be called with the same preset as in the previous example. But that assumption would be wrong! The reason for that is quite simply, that, if the CSS rules would transform the arrow icon and the attribute rules would transform the whole group, both transformations would be applied simultaniously, effectively cancelling each other out (at least in browsers supporting CSS transformations). Attribute and CSS transformations can only safely co-exist, if they define transformations for the very same SVG elements, in which case (as already explained in »Foldable List Items«), the CSS transition overrides the attribute transition.

So, we have to redefine the transformation attribute accordingly:

registerSectionClickHandler(
    $("#sec-al-right-circle2").setupFoldingArrowIconTransformation({
        transformations: [{"path": "scale(1 -1)"}]
    })
); 

Using the "plus" preset and a hover effect

This example picks up the plus preset again, which has already been demonstrated in the list items section, but was actually mainly created to be used this way in a section header.

Here, we don't address a single header by its ID, but we use a class selection for all headers of classes folding-plus and class x:

$("h2.folding-plus.x").prependFoldingArrowIcon({
    preset: "plus",
    viewboxMargin: 3,
    separator: ""
}).setupFoldingArrowIconTransformation({
    preset: "plus"
})
registerSectionClickHandler($("h2.folding-plus.x:not(.altered)"));

By constraining the selector to the additional class x this script setup is specific to this demo with the plus, which should be rotated by 45° to form an X when the section is unfolded.

The following CSS, however, is not constrained to the x class, but is shared with the following demos using a plus, which gets transformed into a minus.

h2.sec.folding-plus a:link, h2.sec.folding-plus a:visited {
    color: #555;
}
h2.sec.folding-plus:hover a, h2.sec.folding-plus a:focus {
    color: #33e;
}
h2.sec.folding-plus .folding-arrow-icon line {
    stroke: #555;
    stroke-width: 3;
    stroke-linecap: round;
}
h2.sec.folding-plus:hover .folding-arrow-icon line {
    stroke: #33e;
}

To demonstrate a further advantage of inline SVG images over external files loaded as img, this demo not only defines a static style for the plus icon, but it adds a hover effect to the whole header, highlighting the text as well as the SVG icon when the mouse cursor hovers over the heading.

"plus-minus" preset

This example only differs from the previous one by loading the "plus-minus" preset which defines a different transformation (plus to minus instead of plus to X):

registerSectionClickHandler(
    $("h2.folding-plus.minus").prependFoldingArrowIcon({
        preset: "plus-minus",
        viewboxMargin: 3,
        separator: ""
    }).setupFoldingArrowIconTransformation({
        preset: "plus-minus"
    })
);

The CSS code is shared with the previous demo.

Manually overriding tranformation

This demo is not intended to be used as blueprint for achieving the plus-to-minus transformation, since that's, what the previously demonstrated "plus-minus" preset is for. It's simply a demo of how you might use plug-in options in order to locally modify the transformation defined by a preset.

So let's assume that the "plus-minus" preset were not available and you wanted to simply use the "plus" preset and override its transformation.

In this example wie use the same classes as in the first "plus" demo and add a further class altered intended to mark a heading where this transformation override should be added to: <h2 class="sec folding-plus al-right x altered" >.

The "plus"-demo's javascript will now be executed first and thus will apply the "plus" preset to this heading, too.
But then we execute a second javascript snippet, which will subsequently alter the transformation setting for this example, defining a different fallback transition attribute for browsers not supporting CSS transformations:

registerSectionClickHandler(
    $("h2.folding-plus.x.altered").setupFoldingArrowIconTransformation({
        transformations: [{"line.v": "scale(1 0)"}]
    })
);

For browsers with CSS transformations support, the CSS has to be overridden, and here that's not just the transformation itself but also the according transition:

h2.folding-plus.x.altered .folding-arrow-icon.plus > g {
    transform: none;
    transition: none;
}
h2.folding-plus.x.altered .folding-arrow-icon.plus line.v {
    transition: transform 0.7s;
}
h2.folding-plus.x.altered.showing .folding-arrow-icon.plus line.v {
    transform: scale(1, 0);
}

Note that in this case (CSS override), we not only add a new transformation to the vertical line of the plus icon (line element of class v as defined by the "plus" preset), but we also have to reset the transformation of the g element, which is usually defined for this preset. In the JavaScript version above that was not necessary, since overwriting the transformations option completely replaces the inherited transformation.

Burger Menu Icon

Though this jQuery plug-in is really mainly made for use cases as demoed above, it can be used for slightly different purposes, too, in which a single icon is needed which can be flipped between two states with a simple transition, combinable with a CSS transition.

A burger icon for opening and closing some menu is one such use case, and for this rather common type if icon, a further preset is included and shall be demoed here. (If it weren't, of course you could use this plug-in's graph option to create your own icon, as already has been demonstrated above.

Click this burger! (In this demo that will not open a menu, but display the example code.)
$("#burger").prependFoldingArrowIcon({
    preset: "burger",
    separator: ""
}).setupFoldingArrowIconTransformation({
    preset: "burger"
}).click(function() {
    ev.preventDefault();
    openOrClose($("#burger"));
    $("#burger-content").slideToggle();
});
#burger .burger-icon {
    width: 40px;
    height: 40px;
    vertical-align: middle;
}

Default CSS styles for elements of the class burger-icon, especially color and line width as well as the transformation and transition are loaded from the included CSS file jquery-folding-arrow-icon.css.