A tiny JavaScript library to easily toggle the state of any HTML element, and create UI components in no time.

Dropdown, navigation button, tooltip, collapsible panel, lightbox, tabs, switch like above to change theme…
UI components made in minutes without worried about JavaScript. Only set a few HTML attributes, and code the rest with your CSS skills.

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.


Demo page

Here is a full demo page where you can find some examples of Easy Toggle State real use cases. In this page, each interactible element is managed with the library, without any JavaScript more.

Easy Toggle State demo page

Examples

Here are some demos to show you how this is powerful.

Of course, these examples can be made in other ways, with Easy Toggle State or not. For example, checkboxes, switchboxes and radio buttons can be made in pure CSS using natives inputs and labels.

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 cases, you can’t.

Loading demo…
Loading demo…
Loading demo…
Loading demo…

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 cases, you can’t.

Loading demo…

Radio buttons

You want to display some radio buttons, i.e. some 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 cases, you can’t.

Loading demo…
Loading demo…
Loading demo…

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.

In most of cases, tooltips are not a good idea for displaying information, and are not accessible to all, screen readers for instance, so please consider not using it, or only for trivial contents.

Loading demo…
Loading demo…

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 cases, you can’t.

Loading demo…
Loading demo…
Loading demo…
Loading demo…

Tabs

You want to create some tabs, i.e. some panels visualizable by clicking on their associated button.

Loading demo…
Loading demo…
Loading demo…

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 cases, you can’t.

Loading demo…
Loading demo…

Quickstart

Locally

Then, add the script into your page:

<script src="./your-path/easy-toggle-state.min.js"></script>

and it’s done.

From CDN

Easy Toggle State is available on some CDN, so you can link it directly from there instead of using it locally.

Go check easy-toggle-state on cdnjs, or use unpkg API.

With NPM

Install with npm:

npm install easy-toggle-state

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

import easyToggle from "easy-toggle-state";
easyToggle();

For example, you could make sure your DOM is fully loaded before initializing Easy Toggle State in your page. To do so:

import easyToggle from "easy-toggle-state";

const handler = () => {
	easyToggle();
	document.removeEventListener("DOMContentLoaded", handler);
};
document.addEventListener("DOMContentLoaded", handler);

Refer to the API using ES modules section to learn more about what you can do.

Browser support

Easy Toggle State library is written in ES2016+, so it supports browsers back to Edge 14, Firefox 43, Chrome 47, Safari 9 and Opera 34.

For more compatibility, you can use the ES5 version, making the library supports browsers back to IE 10, Edge all versions, Firefox 4, Chrome 13, Safari 6 and Opera 12.1.

If you need even more browser compatibility, consider using polyfill.io in addition of the ES5 version. This will make the bundle supports back to IE 8.

Learn more about ES compatibility.


How to use

First recommendation

Although you could use any element, I strongly recommend using only buttons for trigger elements. It’s more accessible, and it’s meant to be used for this kind of thing. The examples will show you that.

If you still want to use links with fake href values, such as href="#", don’t forget to add role="button" attribute.

Toggling

Basis: defining a trigger

Attribute: data-toggle-class
<button data-toggle-class>…</button>

Here is the basic usage: Adding this attribute on a button will make it toggle the CSS class is-active on it on click. It becomes a trigger.

<button data-toggle-class="is-selected">…</button>

You can specify a class name of your own that you want to toggle instead: Here, by clicking on this trigger, the class is-selected will be toggled on it on click.

<button data-toggle-class="class1 class2 class3">…</button>

You can go further into toggling by filling the attribute with as many classes as you need: Here, a click on the trigger will toggle each class on it.

Toggling only on trigger

Attribute: data-toggle-on-trigger
<button data-toggle-class-on-trigger="class1 class2 class3">…</button>

Since you are able to specify a target, you may want to toggle some classes only on the trigger. Here, each of those three classes will be toggled only on this trigger.

Toggling with a target

You may want to add a target to your trigger.

<button data-toggle-class="class" data-toggle-target="selector">…</button>

This way, the class specified in the attribute data-toggle-class will be toggle on this trigger and on its target, defined by the selector.

Toggling only on target

Attribute: data-toggle-on-target
<button data-toggle-class-on-target="class1 class2 class3" data-toggle-target="selector">…</button>

You may want to toggle some classes only on the target. Here, each of those three classes will be toggled only on this target.

Note that this attribute must be used with one of the targeting attributes.

Toggling combinations

You can combine all toggling attributes, making Easy Toggle State compatible with any CSS framwork.

<button
	data-toggle-class="is-open"
	data-toggle-class-on-trigger="text-white font-bold bg-blue"
	data-toggle-class-on-target="text-gray bg-white"
	data-toggle-target="#plop">
	…
</button>

Here, with this combination, a click on this trigger will toggle:

  • the classes is-open, text-white, font-bold, bg-blue on this trigger
  • the classes is-open, text-gray, bg-white on the target, the element #plop

Targeting

Basis: defining a target

Attribute: data-toggle-target
<button data-toggle-class="class" data-toggle-target="selector">…</button>

This is the basics in targeting: the attribute data-toggle-target tells this trigger to look in the whole page for one or several elements to target matching the selector.

This way, a click on the trigger will toggle the class on the trigger itself and on its one or several targets.

The selector value must be a valid CSS selector string, containing one or more selectors to match. Learn more about CSS selectors.

Targeting from the parent

Attribute: data-toggle-target-parent
<button data-toggle-class="class" data-toggle-target-parent="selector">…</button>

Instead of looking in the whole page, you can search for one or several targets matching the selector only inside the trigger’s parent container.

Targeting within the trigger

Attribute: data-toggle-target-self
<button data-toggle-class="class" data-toggle-target-self="selector">…</button>

Instead of looking in the whole page, you can search for one or several targets matching the selector only inside the trigger itself.

See an example with this checkbox.

Targeting the previous sibling element

Attribute: data-toggle-target-previous
<button data-toggle-class="class" data-toggle-target-previous>…</button>

You can target the previous direct sibling element by using data-toggle-target-previous attribute.

Targeting the next sibling element

Attribute: data-toggle-target-next
<button data-toggle-class="class" data-toggle-target-next>…</button>

You can target the next direct sibling element by using data-toggle-target-next attribute.

Advanced

Active by default

Attribute: data-toggle-is-active
<button data-toggle-class="class" data-toggle-is-active>…</button>

Specify a trigger element and its targets to be active by default. As a consequence, they will be toggled once on initialization.

See an example with tabs.

Grouping triggers

Attribute: data-toggle-group
<button data-toggle-class="class" data-toggle-group="name">…</button>
<button data-toggle-class="class" data-toggle-group="name">…</button>

Specify that a trigger is a part of a group, defined by a name. Only one trigger of a group can be active at a time. Of course, it must be used on at least two triggers to create a group.

They will actually behave like an accordion component.

Attribute: data-toggle-radio-group
<button data-toggle-class="class" data-toggle-radio-group="name">…</button>
<button data-toggle-class="class" data-toggle-radio-group="name">…</button>

Specify that they are a part of a radio group, defined by a name. Only one trigger of a radio group can be active at a time. Of course, it must be used on at least two triggers to create a group.

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

Note that a trigger of a radio grouped can’t have data-toggle-outside[?] or data-toggle-escape[?] behavior.

Toggle on another event

Attribute: data-toggle-event
<button data-toggle-class="class" data-toggle-event="event">…</button>

Specify another event to toggle the trigger instead of the click event used by default. For example, mouseover.

See an example with a tooltip.

Toggle off when outside

Attribute: data-toggle-outside
<button data-toggle-class="class" data-toggle-outside>…</button>

When a trigger is active, specify to toggle off this trigger when you click again outside of it. If you use the data-toggle-event[?] attribute too on the trigger, the event used is the same.

Note that this attribute does not work on an element with data-toggle-radio-group[?].

See an example with a dropdown.

Attribute: data-toggle-outside-event
<button
		data-toggle-class="class"
		data-toggle-outside
		data-toggle-outside-event="event">
		…
</button>

When using data-toggle-outside[?] attribute, add this attribute to use a different event to toggle off outside of the trigger.

Note that this attribute only works when used in addition of data-toggle-outside[?] attribute.

See an example with a tooltip.

Keyboard support

Attribute: data-toggle-escape
<button data-toggle-class="class" data-toggle-escape>…</button>

Specify that you can press the escape key to toggle off the trigger when it is already active.

Note that this attribute does not work on an element with data-toggle-radio-group[?].

See an example with a collapsible panel.

Attribute: data-toggle-arrows
<button data-toggle-class="class" data-toggle-arrows data-toggle-group="name">…</button>
<button data-toggle-class="class" data-toggle-arrows data-toggle-group="name">…</button>

Used with a group attribute, specify that as soon as a trigger is focused, you can navigate through the 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[?].

See an example with radio buttons.

Targeting a modal

Attribute: data-toggle-modal
<button data-toggle-class="class" data-toggle-modal>…</button>

Specify that the target is a modal, such as a dialog or a lightbox. This way, when the target is active (open), the focus is trapped inside this target until you close it. This means tabbing will only focus on focusable elements inside this target, leaving anything else outside be out of scope.

Be very careful when using this feature. A focus trap can be very annoying (and an accessibility fault) when used in a wrong way, so be sure your target is a modal component.

Closing button

Attribute: data-toggle-trigger-off
<button data-toggle-class="class" data-toggle-target="#plop">…</button>

<div id="plop">
	<button data-toggle-trigger-off="#plop">…</button>
</div>

This attribute is meant to be used on an element inside a target. By doing so, it enables this element to toggle the related trigger back off when it is active. For example, a close button inside a dialog or a lightbox.

Fill this attribute with a CSS selector matching that target element.

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

Accessibility

If a trigger or a target element has one of the supported ARIA attributes, its value will also change, so please consider using the right roles and ARIA attributes to optimize your components for accessibility.

The examples will help you for that. Learn more about ARIA.

The ARIA attributes supported by Easy Toggle State are:

  • aria-checked
  • aria-expanded
  • aria-hidden
  • aria-pressed
  • aria-selected

Customization

You can change the prefix toggle in data-toggle-class and other 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.

API

API using the bundle (locally or from CDN)

initialization

Initialize all trigger elements not yet binded.

window.easyToggleState();

No parameter. Returns an Array of newly initialized trigger elements.

unbind

Unbind a trigger element, or a trigger element list.

window.easyToggleState.unbind( Node || NodeList );

Takes a Node or a NodeList as parameter. Returns the same Node or NodeList.

unbindAll

Unbind all trigger elements.

window.easyToggleState.unbindAll();

No parameter. Returns a NodeList of all newly unbinded trigger elements.

isActive

Get the state of a trigger element.

window.easyToggleState.isActive( Node );

Takes a Node as parameter. Returns a boolean.

API using ES modules

initialization

Initialize all trigger elements not yet binded.

import initialize from "easy-toggle-state";
initialize();

No parameter. Returns an Array of newly initialized trigger elements.

unbind

Unbind a trigger element, or a trigger element list.

import { unbind } from "easy-toggle-state";
unbind( Node || NodeList );

Takes a Node or a NodeList as parameter. Returns the same Node or NodeList.

unbindAll

Unbind all trigger elements.

import { unbindAll } from "easy-toggle-state";
unbindAll();

No parameter. Returns a NodeList of all newly unbinded trigger elements.

isActive

Get the state of a trigger element.

import { isActive } from "easy-toggle-state";
isActive( Node );

Takes a Node as parameter. Returns a boolean.

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.

For example:

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

Contribution