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.

Download – 4,76ko
Compressed, for production
Download – 14,40ko
Uncompressed, for development
View on GitHub
Navigation icon Go to navigation

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

Manually

Then, add the script into your page, and it’s done.

With npm

Install with npm:

npm install easy-toggle-state

Then load Easy Toggle State into your application, inside your main JS file:

import "easy-toggle-state";
// or
require("easy-toggle-state");

and the magic happens!

Compatibility

In addition of using ES5 version, compatibility for Internet Explorer is provided by polyfill.io which supports back to IE 7. It brings polyfills for Array.from, Array.prototype.filter, Element.prototype.closest and more.

And before you ask, yes, you can run it locally.


How to use

Recommendation

Although you could use any element you want, I recommend using only buttons or links as trigger elements. For links with a fake href value, such as href="#", don’t forget to add 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, even if the script will check that for you.

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 an accordion component.

data-toggle-radio-group="groupName"

Specify if a trigger is a part of a radio group. Only one trigger of a radio group can be active at a time.

Unlike a simple group as seen above, as soon as a trigger is activated, a radio group will always keep one trigger active. It will actually behave like radio buttons or tabs component.

Note that a radio grouped trigger can’t have data-toggle-outside or data-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 of 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 pressed.

data-toggle-arrows

Specify that when a grouped trigger is focused, you can navigate between other triggers of the same group with arrows , home and end keys.

Remember that this attribute must be used with data-toggle-group or data-toggle-radio-group.

data-toggle-trigger-off

Add this attribute to an element inside a target to enable it to toggle the state of this target. For example, a close button in a modal.

Remember that this attribute must be used on an element inside a target.

Accessibility

If a trigger or a target element has the aria-expanded, aria-selected, aria-checked or aria-hidden attribute, its value will also change.

Expert

Custom prefix

You can change the prefix toggle in data-toggle-class and every attributes to prevent conflict with another JS library. To do so, add this attribute to your <html> element with your new prefix:

<html data-easy-toggle-state-custom-prefix="my-prefix">

It will so be set to all attributes like data-my-prefix-class.

Asynchronous needs

For asynchronous needs, you can initiate the magic with:

window.initEasyToggleState();

Hooks

You can also add some hooks: each trigger and target element fires a toggleBefore event before and a toggleAfter event after toggling its state, so you can add event listeners on these events, and test the active state with isToggleActive property. For example:

document.querySelector("#myTrigger").addEventListener("toggleAfter", (event) => {
	console.log(`Active: ${event.target.isToggleActive}`);
}, false);

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 component, in some case, you can’t.

Simple checkbox

<button type="button"
	class="example-checkbox"
	data-toggle-class="is-checked">
</button>
download CSS - SCSS -

Checkbox with ARIA attributes for accessibility

<button type="button"
	class="example-checkbox"
	data-toggle-class="is-checked"
	role="checkbox"
	aria-checked="false"
	title="Toggle this box">
	<span class="sr-only">Toggle</span>
</button>
download CSS - SCSS -

Checkbox with external label

<button type="button"
	class="example-checkbox"
	data-toggle-class="is-checked"
	id="checkbox"
	role="checkbox"
	aria-checked="false"
	title="Toggle this box">
	<span class="sr-only">Toggle</span>
</button>
<label for="checkbox">
	Awesome checkbox
</label>
download CSS - SCSS -

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" aria-hidden="true"></span>
	Awesome checkbox
</button>
download CSS - SCSS -

Explanation

Toggle .is-checked class on click on the box. As aria-checked attribute is set, its value change too.

The CSS class .sr-only is for hiding content for accessibility.

Switchbox

You want to display a switchbox, i.e. a box with a "ball" that moves on click on this box. Even if you should use the <input type="checkbox"> native component, in some case, you can’t.

In this example, the HTML code is actually the same as a checkbox with external label, only CSS code changes.

Switchbox with external label

<button type="button"
	class="example-switchbox"
	data-toggle-class="is-checked"
	id="switchbox"
	role="checkbox"
	aria-checked="false"
	title="Toggle this box">
	<span class="sr-only">Toggle</span>
</button>
<label for="switchbox">
	Awesome switchbox
</label>
download CSS - SCSS -

Explanation

Toggle .is-checked class on click on the box. As aria-checked attribute is set, its value change too.

The CSS class .sr-only is for hiding content for accessibility.

Radio buttons

You want to display some radio buttons, i.e. somes circles which are filled on click on them, only one at a time. Even if you should use the <input type="radio"> native component, 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-radio-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-radio-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-radio-group="radioGroup">
</button>
<label for="radio_3">Option 3</label>


download CSS - SCSS -

Radio buttons with arrow keys support

<button type="button"
	class="example-radio"
	id="radio_1"
	data-toggle-class="is-checked"
	data-toggle-radio-group="radioGroup"
	data-toggle-arrows>
</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-radio-group="radioGroup"
	data-toggle-arrows>
</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-radio-group="radioGroup"
	data-toggle-arrows>
</button>
<label for="radio_3">Option 3</label>


download CSS - SCSS -

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-radio-group="radioGroup"
		role="radio"
		aria-checked="false"
		title="Toggle this box">
		<span class="sr-only">Toggle</span>
	</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-radio-group="radioGroup"
		role="radio"
		aria-checked="false"
		title="Toggle this box">
		<span class="sr-only">Toggle</span>
	</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-radio-group="radioGroup"
		role="radio"
		aria-checked="false"
		title="Toggle this box">
		<span class="sr-only">Toggle</span>
	</button>
	<label for="radio_3">Option 3</label>

</div>


download CSS - SCSS -

Explanation

Toggle .is-checked class on click on this element, but only one of the radioGroup group at a time, and always keep one active. As aria-checked attribute is set, its value change too.

Thanks to data-toggle-arrows attribute, you can navigate between options with arrow keys as soon as one option is focused.

The label is associated to the trigger by the for attribute.

The CSS class .sr-only is for hiding content for accessibility.

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
	aria-describedby="tooltip_id">
	Hover me
	<span class="tooltip"
		id="tooltip_id"
		role="tooltip"
		aria-hidden="true">
		Awesome tooltip
	</span>
</span>
Hover me
download CSS - SCSS -

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>
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.
download CSS - SCSS -

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>
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.
download CSS - SCSS -

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>
download CSS - SCSS -

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-escape
	data-toggle-arrows
	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"
	data-toggle-escape
	data-toggle-arrows
	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>

<!-- … -->
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.
download CSS - SCSS -

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. Thanks to data-toggle-arrows attribute, you can also navigate between panels with arrow keys as soon as one tab is focused.

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-radio-group="tabsGroup"
		data-toggle-is-active>
		tab 1
	</button>
	<button type="button"
		data-toggle-class
		data-toggle-target="#tabPanel_2"
		data-toggle-radio-group="tabsGroup">
		tab 2
	</button>
	<button type="button"
		data-toggle-class
		data-toggle-target="#tabPanel_3"
		data-toggle-radio-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>
Panel 1
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.
Panel 2
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.
Panel 3
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.
download CSS - SCSS -

Tabs with arrow keys support

<div class="example-tabs">
	<button type="button"
		data-toggle-class
		data-toggle-target="#tabPanel_1"
		data-toggle-radio-group="tabsGroup"
		data-toggle-arrows
		data-toggle-is-active>
		tab 1
	</button>
	<button type="button"
		data-toggle-class
		data-toggle-target="#tabPanel_2"
		data-toggle-radio-group="tabsGroup"
		data-toggle-arrows>
		tab 2
	</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>
<!-- … -->
Panel 1
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.
Panel 2
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.
Panel 3
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.
Panel 4
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.
Panel 5
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.
Panel 6
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.
download CSS - SCSS -

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-radio-group="tabsGroup"
		data-toggle-arrows
		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-radio-group="tabsGroup"
		data-toggle-arrows
		role="tab"
		aria-selected="false"
		aria-controls="tabPanel_2">
		tab 2
	</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>
<!-- … -->
Panel 1
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.
download CSS - SCSS -

Explanation

Toggle .is-active class – by default – on click on this element, but only one of the tabsGroup group at a time, and always keep one active. 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. Since data-toggle-radio-group is used instead of data-toggle-group, this group will always keep one of its triggers active. The first panel is opened by default with data-toggle-is-active. Thanks to data-toggle-arrows attribute, you can also navigate between panels with arrow keys as soon as one tab is focused.

As aria-selected and aria-hidden attributes are set, their value change too.

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.

download CSS - SCSS -

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>
download CSS - SCSS -

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.


Contribution