A tiny JavaScript library to easily toggle the state of any HTML element and its targets.
Dropdown, navigation button, tooltip, collapsible panel, lightbox, tabs, switch like above…
UI components made in minutes without worried about JavaScript. Only set a few HTML attributes, and code the rest with your CSS skills.
Compressed, for production Download – 11,0ko
Uncompressed, for development View on GitHub
Why?
A front-end developer often has to code scripts for interface components. Components such as dropdowns, navigation buttons, tooltips, expandable panels, lightboxes, tabs, etc.
The thing is… Most of these components expose a recurrent behavior: a trigger element toggles the state of one or more target elements. So why not code this behavior once and for all?
So here is a solution: a simple script to toggle the state of a trigger element with a CSS class. You can then associate this element with one or more others: letās call them targets. By adding the right HTML attributes, it can adapt to any contexts and behave like a chosen component.
Only focus on adjusting the rest with your CSS creativity.
Quick start
Several quick start options are available:
- Direct download
- Choose another version: ES5, ES6 or a build for IE11 with polyfills
-
Clone the repo:
git clone https://github.com/twikito/easy-toggle-state.git
-
Install with npm:
npm install easy-toggle-state
Then, add the script into your page, and itās done.
How to use
Recommendation
Although you could use any element you want, I recommend using only buttons or links as trigger elements. For a link element with a fake href
value, donāt forget to add the role="button"
attribute.
Basics
-
<foo data-toggle-class="class-name">
-
A CSS class to toggle each time a click is triggered on this element. If empty, the
is-active
class is used. -
<foo data-toggle-class="class-name" data-toggle-target="selector">
-
Toggle the class on the trigger element and all the target elements, defined by the selector, in the page. This attribute has
data-toggle-target-all
as alias.
Targeting
You can go further in selecting targets by using one of the following options: it specify a scope where to select targets.
-
<foo data-toggle-class="class-name" data-toggle-target="selector">
-
Basic targeting: Toggle the class on the trigger element and all the target elements, defined by the selector, in the whole page. This attribute has
data-toggle-target-all
as alias. -
<foo data-toggle-class="class-name" data-toggle-target-parent="selector">
-
Toggle the class on the trigger element and all the target elements, defined by the selector, belonging to its parent container.
-
<foo data-toggle-class="class-name" data-toggle-target-self="selector">
-
Toggle the class on the trigger element and all the target elements, defined by the selector, within it.
-
<foo data-toggle-class="class-name" data-toggle-target-previous>
-
Toggle the class on the trigger element and its previous adjacent element.
-
<foo data-toggle-class="class-name" data-toggle-target-next>
-
Toggle the class on the trigger element and its next adjacent element.
Advanced
-
data-toggle-is-active
-
Specify a trigger element and its targets toggled as default, set during the
onload
event. In this case, you should add the specified class name on each element. -
data-toggle-group="groupName"
-
Specify if a trigger is a part of a group. Only one trigger of a group can be active at a time. It will actually behave like radio buttons or tabs component.
Note that a grouped trigger canāt have
data-toggle-outside
ordata-toggle-escape
behavior. -
data-toggle-event="event"
-
Specify the event that will toggle the class,
mouseover
for example.click
by default if not specified. -
data-toggle-outside
-
Toggle off the class when the event is triggered again outside the trigger element.
-
data-toggle-target-only
-
Toggle the class only on the target elements.
-
data-toggle-escape
-
Toggle the class when the trigger element is active and when the escape key is released.
-
data-toggle-trigger-off
-
Add this attribute to an element inside a target to enable this element to toggle the behavior. For example, a close button in a modal.
More
If a trigger or a target element has the aria-expanded
, aria-selected
, aria-checked
or aria-hidden
attribute, its value will also change.
You can also change the PREFIX
value to prevent conflict with another JS library. This prefix will be set to all attributes like data-[PREFIX]-class
, toggle
as default.
Finally, for asynchronous needs, you can call window.initEasyToggleState()
.
Examples
Here are some demos to show you how this is powerful. Of course, these examples can be made in other ways.
Checkbox
You want to display a checkbox, i.e. a box with a checkmark that appears on click on this box.
Even if you should use the <input type="checkbox">
native componant, in some case, you canāt.
Simple checkbox
<button type="button"
class="example-checkbox"
data-toggle-class="is-checked">
</button>
Checkbox with ARIA attributes for accessibility
<button type="button"
class="example-checkbox"
data-toggle-class="is-checked"
role="checkbox"
aria-checked="false">
</button>
Checkbox with external label
<button type="button"
class="example-checkbox"
data-toggle-class="is-checked"
id="checkbox"
role="checkbox"
aria-checked="false">
</button>
<label for="checkbox">
Awesome checkbox
</label>
Checkbox with internal label
<button type="button"
class="example-checkbox-container"
data-toggle-class="is-checked"
data-toggle-target-self=".example-checkbox"
role="checkbox"
aria-checked="false">
<span class="example-checkbox"></span>
Awesome checkbox
</button>
Explanation
Toggle .is-checked
class on click on the box. As aria-checked
attribute is set, its value change too.
Radio buttons
You want to display some radio buttons, i.e. somes boxes with a checkmark that appears on click on these boxes, only one at a time.
Even if you should use the <input type="radio">
native componant, in some case, you canāt.
Simple radio buttons
<button type="button"
class="example-radio"
id="radio_1"
data-toggle-class="is-checked"
data-toggle-group="radioGroup">
</button>
<label for="radio_1">Option 1</label><br>
<button type="button"
class="example-radio"
id="radio_2"
data-toggle-class="is-checked"
data-toggle-group="radioGroup">
</button>
<label for="radio_2">Option 2</label><br>
<button type="button"
class="example-radio"
id="radio_3"
data-toggle-class="is-checked"
data-toggle-group="radioGroup">
</button>
<label for="radio_3">Option 3</label>
Radio buttons with ARIA attributes for accessibility
<div role="radiogroup">
<button type="button"
class="example-radio"
id="radio_1"
data-toggle-class="is-checked"
data-toggle-group="radioGroup"
role="radio"
aria-checked="false">
</button>
<label for="radio_1">Option 1</label><br>
<button type="button"
class="example-radio"
id="radio_2"
data-toggle-class="is-checked"
data-toggle-group="radioGroup"
role="radio"
aria-checked="false">
</button>
<label for="radio_2">Option 2</label><br>
<button type="button"
class="example-radio"
id="radio_3"
data-toggle-class="is-checked"
data-toggle-group="radioGroup"
role="radio"
aria-checked="false">
</button>
<label for="radio_3">Option 3</label>
</div>
Explanation
Toggle .is-checked
class on click on this element, but only one of the radioGroup
group at a time. As aria-checked
attribute is set, its value change too.
The label is associated to the trigger by the for
attribute.
Tooltip
You want to put a tooltip on a text, i.e. show an element when hovering this text, and hide it when the cursor leaves this text.
Simple tooltip
<span class="example-tooltip"
data-toggle-class="is-visible"
data-toggle-target-self=".tooltip"
data-toggle-target-only
data-toggle-event="mouseover"
data-toggle-outside>
Hover me
<span class="tooltip" aria-hidden="true">Awesome tooltip</span>
</span>
Explanation
Toggle .is-visible
class only on the target .tooltip
located inside this trigger, on mouseover
event, and toggle again when mouseover
is triggered outside this trigger.
As aria-hidden
attribute is set, its value change too.
Collapsible panel / accordion
You want to create a collapsible panel, i.e. a frame, with some content, that can be collapsed on click on a button.
Even if you should use <details>
and <summary>
HTML elements, in some case, you canāt.
Simple collapsible panel
<button type="button"
class="example-collapsible-button"
data-toggle-class="is-open"
data-toggle-target-next>
Click here
</button>
<div class="example-collapsible-panel">
<div class="example-collapsible-panel-content">
Lorem ipsum dolor sit amet…
</div>
</div>
Collapsible panel with escape key support
<button type="button"
class="example-collapsible-button"
data-toggle-class="is-open"
data-toggle-target-next
data-toggle-escape>
Click here
</button>
<div class="example-collapsible-panel">
<div class="example-collapsible-panel-content">
Lorem ipsum dolor sit amet…
</div>
</div>
Collapsible panel with ARIA attributes for accessibility
<button type="button"
class="example-collapsible-button"
id="buttonForPanel"
data-toggle-class="is-open"
data-toggle-target-parent="#panel"
data-toggle-escape
aria-controls="panel"
aria-expanded="false">
Click here
</button>
<div class="example-collapsible-panel"
id="panel"
role="region"
aria-labelledby="buttonForPanel"
aria-hidden="true">
<div class="example-collapsible-panel-content">
Lorem ipsum dolor sit amet…
</div>
</div>
Accordion
<!-- First panel, opened by default -->
<button type="button"
class="example-collapsible-button"
id="buttonForPanel_1"
data-toggle-class="is-open"
data-toggle-target-parent="#panel_1"
data-toggle-group="accordion"
data-toggle-is-active
aria-controls="panel_1"
aria-expanded="true">
Click here
</button>
<div class="example-collapsible-panel"
id="panel_1"
role="region"
aria-labelledby="buttonForPanel_1"
aria-hidden="false">
<div class="example-collapsible-panel-content">
Lorem ipsum dolor sit amet…
</div>
</div>
<!-- Second panel -->
<button type="button"
class="example-collapsible-button"
id="buttonForPanel_2"
data-toggle-class="is-open"
data-toggle-target-parent="#panel_2"
data-toggle-group="accordion"
aria-controls="panel_2"
aria-expanded="false">
Click here
</button>
<div class="example-collapsible-panel"
id="panel_2"
role="region"
aria-labelledby="buttonForPanel_2"
aria-hidden="true">
<div class="example-collapsible-panel-content">
In in erat blandit ante mollis tincidunt…
</div>
</div>
<!-- Third panel -->
<button type="button"
class="example-collapsible-button"
id="buttonForPanel_3"
data-toggle-class="is-open"
data-toggle-target-parent="#panel_3"
data-toggle-group="accordion"
aria-controls="panel_3"
aria-expanded="false">
Click here
</button>
<div class="example-collapsible-panel"
id="panel_3"
role="region"
aria-labelledby="buttonForPanel_3"
aria-hidden="true">
<div class="example-collapsible-panel-content">
Nam posuere tortor a augue vulputate…
</div>
</div>
Explanation
The button toggles .is-open
class on itself and its target located inside its parent container. If thereās more than one button / panel, be careful to target a unique ID.
For an accordion, each trigger must be linked to the same group, here accordion
. This way, only one of this group can be opened at a time. The first panel is opened by default with data-toggle-is-active
.
As aria-expanded
and aria-hidden
attributes are set, their value change too.
Tabs
You want to create some tabs, i.e. some panels visualisable by clicking on their associated button.
Simple tabs
<div class="example-tabs">
<button type="button"
data-toggle-class
data-toggle-target="#tabPanel_1"
data-toggle-group="tabsGroup"
data-toggle-is-active>
tab 1
</button>
<button type="button"
data-toggle-class
data-toggle-target="#tabPanel_2"
data-toggle-group="tabsGroup">
tab 2
</button>
<button type="button"
data-toggle-class
data-toggle-target="#tabPanel_3"
data-toggle-group="tabsGroup">
tab 3
</button>
</div>
<div class="example-tab-panel" id="tabPanel_1">
Panel 1<br>
Lorem ipsum dolor sit amet…
</div>
<div class="example-tab-panel" id="tabPanel_2">
Panel 2<br>
In in erat blandit ante mollis tincidunt…
</div>
<div class="example-tab-panel" id="tabPanel_3">
Panel 3<br>
Nam posuere tortor a augue vulputate…
</div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper faucibus odio, vitae faucibus dui tempor in. Duis vitae luctus mi. Phasellus ultrices rhoncus lectus, non vehicula tortor sodales id.
In in erat blandit ante mollis tincidunt. Quisque ac tempus nisi, a ultricies metus. Suspendisse et quam nec mauris feugiat luctus. Curabitur porta sem vitae nulla congue malesuada.
Nam posuere tortor a augue vulputate, at blandit ipsum tincidunt. Donec dictum eros ligula, id congue justo porta eget. Aliquam vel erat venenatis, ornare nisi vel, convallis libero.
Tabs with ARIA attributes for accessibility
<div class="example-tabs" role="tablist">
<button type="button"
id="tab_1"
data-toggle-class
data-toggle-target="#tabPanel_1"
data-toggle-group="tabsGroup"
data-toggle-is-active
role="tab"
aria-selected="true"
aria-controls="tabPanel_1">
tab 1
</button>
<button type="button"
id="tab_2"
data-toggle-class
data-toggle-target="#tabPanel_2"
data-toggle-group="tabsGroup"
role="tab"
aria-selected="false"
aria-controls="tabPanel_2">
tab 2
</button>
<button type="button"
id="tab_3"
data-toggle-class
data-toggle-target="#tabPanel_3"
data-toggle-group="tabsGroup"
role="tab"
aria-selected="false"
aria-controls="tabPanel_3">
tab 3
</button>
</div>
<div class="example-tab-panel"
id="tabPanel_1"
role="tabpanel"
aria-labelledby="tab_1"
aria-hidden="false">
Panel 1<br>
Lorem ipsum dolor sit amet…
</div>
<div class="example-tab-panel"
id="tabPanel_2"
role="tabpanel"
aria-labelledby="tab_2"
aria-hidden="true">
Panel 2<br>
In in erat blandit ante mollis tincidunt…
</div>
<div class="example-tab-panel"
id="tabPanel_3"
role="tabpanel"
aria-labelledby="tab_3"
aria-hidden="true">
Panel 3<br>
Nam posuere tortor a augue vulputate…
</div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper faucibus odio, vitae faucibus dui tempor in. Duis vitae luctus mi. Phasellus ultrices rhoncus lectus, non vehicula tortor sodales id.
Explanation
Toggle .is-active
class ā by default ā on click on this element, but only one of the tabsGroup
group at a time. Toggle the same class on the target element. As thereās more than one button / panel, be careful to target a unique ID.
Each trigger must be linked to the same group, here tabsGroup
. This way, only one of this group can be opened at a time. The first panel is opened by default with data-toggle-is-active
.
As aria-selected
and aria-hidden
attributes are set, their value change too.
Dropdown
You want to create a dropdown, i.e. a list of choices that appears when you click on a button. Of course you should use <select>
and <option>
HTML elements, but in some case, you canāt.
Simple dropdown
<div class="example-dropdown">
<button type="button"
class="example-dropdown-button"
data-toggle-class="is-open"
data-toggle-target-next
data-toggle-outside
data-toggle-escape>
Select something here
</button>
<ul class="example-dropdown-list">
<li>
<button type="button">Lorem ipsum dolor</button>
</li>
<!-- Several options -->
</ul>
</div>
Dropdown with ARIA attributes for accessibility
<div class="example-dropdown">
<button type="button"
class="example-dropdown-button"
data-toggle-class="is-open"
data-toggle-target-next
data-toggle-outside
data-toggle-escape
id="dropdownButton"
aria-haspopup="listbox"
aria-controls="dropdownList"
aria-expanded="false">
Select something here
</button>
<ul class="example-dropdown-list"
id="dropdownList"
role="listbox"
aria-labelledby="dropdownButton"
aria-hidden="true">
<li>
<button type="button">Lorem ipsum dolor</button>
</li>
<!-- Several options -->
</ul>
</div>
Explanation
Toggle .is-open
class on click on this element. Toggle the class on its target, the next adjacent element, at the same time. Click outside of the trigger or its target, or press escape key to toggle off.
You could also add data-toggle-trigger-off
attribute on each option button to toggle off dropdownās state by clicking on them.
As aria-expanded
and aria-hidden
attributes are set, their value change too.
Note: You can not change the value of the trigger by clicking on an option with this script. Easy Toggle State only deal with changing state. You will have to do this by yourself.
Dialog
You want to create a dialog, i.e. an information or form box displayed in front of all page content on click on a trigger.
Even if you should use <dialog>
HTML element, in some case, you canāt.
Simple dialog
<button type="button"
class="example-dialog-trigger"
data-toggle-class
data-toggle-target="#dialog"
data-toggle-target-only
data-toggle-escape>
Click to see the awesomeness
</button>
<!-- This dialog anywhere you want in the page -->
<div class="example-dialog" id="dialog">
<section class="example-dialog-container">
<!-- Your content here, like text or form. -->
<button type="button" data-toggle-trigger-off>close</button>
</section>
</div>
Dialog title
Any content you want, like text or form.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Dialog with ARIA attributes for accessibility
<button type="button"
class="example-dialog-trigger"
data-toggle-class
data-toggle-target="#dialog"
data-toggle-target-only
data-toggle-escape>
Click to see the awesomeness
</button>
<!-- This dialog anywhere you want in the page -->
<div class="example-dialog"
id="dialog"
role="dialog"
aria-labelledby="dialogTitle"
aria-describedby="dialogContent"
aria-hidden="true">
<section class="example-dialog-container">
<header id="dialogTitle" class="example-dialog-header">
Dialog title
</header>
<div id="dialogContent" class="example-dialog-content">
<!-- Your content here, like text or form. -->
</div>
<footer class="example-dialog-footer">
<button type="button" data-toggle-trigger-off>close</button>
</footer>
</section>
</div>
Explanation
Toggle .is-active
class ā as default ā on click on this element. Toggle the class on its target #dialog
, placed anywhere in the page ā at the bottom for example ā, at the same time. Press escape key to toggle off.
The attribute data-toggle-trigger-off
enable the ācloseā button to toggle off dialogās state by clicking on it.
As aria-hidden
attribute is set, its value change too.
Lightbox
You want to create a lightbox, i.e. a box displayed in front of all page content to see a larger version of an image.
Simple lightbox
<a class="example-lightbox-trigger"
href="image-lg.jpg"
title="Zoom"
data-toggle-class
data-toggle-target-parent=".example-lightbox"
data-toggle-target-only
data-toggle-escape>
<img src="image.jpg" alt="desc">
</a>
<div class="example-lightbox" role="dialog" aria-hidden="true">
<div class="example-lightbox-bg"
data-toggle-trigger-off>
</div>
<button type="button"
class="example-lightbox-close"
data-toggle-trigger-off
title="close">
ā
</button>
<img class="example-lightbox-img" src="image-lg.jpg" alt="desc">
</div>
Explanation
Toggle .is-active
class ā as default ā on click on this element. Toggle the class on its target .example-lightbox
, belonging to its parent container, at the same time. Press escape key to toggle off.
The attribute data-toggle-trigger-off
enable the ācloseā button and the opacified black background to toggle off lightbox state by clicking on them.
As aria-hidden
attribute is set, its value change too.
Burger icon
You want to create a burger icon, i.e. an icon that represent a button you can click on to make a navigation menu visible.
Simple burger icon
<button type="button"
class="example-nav-trigger"
title="Navigation"
data-toggle-class
data-toggle-escape>
<svg width="1em" class="example-nav-trigger-icon" role="img" viewBox="0 0 100 100">
<title>Navigation icon</title>
<rect class="top-bar" x="0" y="15" width="100" height="12"/>
<rect class="mid-bar" x="0" y="44" width="100" height="12"/>
<rect class="bot-bar" x="0" y="73" width="100" height="12"/>
</svg>
</button>
Explanation
Toggle .is-active
class ā by default ā on click on this element. data-toggle-escape
attribute means you can press escape key to toggle off.
You will probably add data-toggle-target
attribute with the ID of your navigation bar to toggle it at the same time.
Consider adding some ARIA attributes for accessibility. Refer to other examples above.
Contribution
- Fork repository on GitHub
- Report a bug
- Suggest a feature
- Development:
$ npm run build