npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ctrly

v0.7.0

Published

Lightweight and dependency-free content toggling with a focus on accessibility.

Downloads

167

Readme

ctrly

Lightweight and dependency-free content toggling with a focus on accessibility.

Build Status BrowserStack Status

About

ctrly is a lightweight library which tries to solve 80% of the use-cases where a control (usually a <button> element) toggles the visibility of a target element.

It can be used to implement dropdown or off-canvas menus, modals, accordions and similar UI elements. Example implementations can be found in the examples/ directory.

Demos: AccordionDropdownOffcanvas

Minified and gzipped, the total footprint weights about 2.8kB.

Installation

The recommended way to install ctrly is via npm.

npm install ctrly

After installation, ctrly can be imported as a module.

import ctrly from 'ctrly';

The latest version can also be downloaded or included from unpkg or jsDelivr.

<script src="/path/to/ctrly.js"></script>

The ctrly() function is then globally available.

Usage

A typical setup includes a control (usually a <button> element) which toggles the visibility of a target element.

The control must have a data-ctrly attribute which must contain the ID of the target.

<button data-ctrly="my-target">Toggle</button>
<section id="my-target">You clicked the toggle to make me visible</section>

To initialize all controls, the ctrly() function must be called once.

ctrly();

ctrly then adds all required ARIA attributes:

  • The aria-controls and aria-expanded attributes to the control.
  • The aria-hidden and aria-labelledby to the target.

If the control does not have an id attribute, ctrly will add an auto-generated ID.

The fully generated HTML looks like the following.

<button
    data-ctrly="my-target"
    id="ctrly-control-1"
    aria-controls="my-target"
    aria-expanded="false"
>
    Toggle
</button>
<section
    id="my-target"
    aria-hidden="false"
    aria-labelledby="ctrly-control-1"
>
    You clicked the toggle to make me visible
</section>

Note: ctrly does not ship with any default CSS which shows and hides the target element as it makes no assumptions on how the visibility is controlled.

This must be implemented depending on the aria-hidden attribute which is toggled to either false or true by ctrly.

/* Toggle via the display property */
.target-selector[aria-hidden="true"] {
    display: none;
}

/* Toggle via the visibility property */
.target-selector[aria-hidden="true"] {
    visibility: hidden;
}

It is also good practice to hide the controls if JavaScript is disabled.

This can be done depending on the presence of the aria-controls attribute added by ctrly.

.control-selector:not([aria-controls]) {
    display: none;
}

While it is highly recommended to use <button> elements as controls, ctrly also supports other HTML elements.

<span data-ctrly="my-target">Toggle</button>

The fully generated HTML looks like the following (note the additional tabindex, role and aria-pressed attributes).

<span
    data-ctrly="my-target"
    id="ctrly-control-1"
    aria-controls="my-target"
    aria-expanded="false"
    tabindex="0"
    role="button"
    aria-pressed="false"
>
    Toggle
</span>

API

The return value of the ctrly() function is an object with the following functions.

closeAll

This function closes all open targets.

Example

const { closeAll } = ctrly();

closeAll();

destroy

This function reverts all elements to their initial state and unbinds all event listeners.

Example

const { destroy } = ctrly();

destroy();

init

This function (re)initializes all controls. This can be useful after the DOM has been updated, eg. controls have been added dynamically.

Example

const { init } = ctrly();

init();

Options

ctrly's behavior can be controlled by passing an options object as the first argument.

ctrly({
    // Options...
});

The following options are available.

selector

Default: [data-ctrly]

A selector for the control elements.

Example

<button class="my-control" data-ctrly="my-target">Toggle</button>
ctrly({
    selector: '.my-control'
});

context

Default: null

A selector to group targets together. Can be used in combination with the allowMultiple option to allow or disallow multiple open targets inside a context.

See the accordion example for a use-case.

Example

<div class="my-context">
    <button data-ctrly="my-target">Toggle</button>
</div>
<div class="my-context">
    <button data-ctrly="my-target">Toggle</button>
</div>
ctrly({
    context: '.my-context'
});

focusTarget

Default: true

By default, once the target becomes visible, the focus is shifted to the first focusable element inside the target. Passing false as an option disables this behavior.

Example

ctrly({
    focusTarget: false
});

closeOnBlur

Default: true

By default, targets are closed when the focus is shifted from an element inside the target to an element outside the target. Passing false as an option disables this behavior.

This setting is always false if trapFocus is set to true.

Example

ctrly({
    closeOnBlur: false
});

closeOnEsc

Default: true

By default, targets are closed when the ESC key is pressed. Passing false as an option disables this behavior.

Example

ctrly({
    closeOnEsc: false
});

closeOnOutsideClick

Default: true

By default, targets are closed when there is a mouse click outside the target. Passing false as an option disables this behavior.

Example

ctrly({
    closeOnOutsideClick: false
});

closeOnScroll

Default: false

Passing true as an option closes a target when the window is scrolled and the mouse is currently not inside the target element.

Example

ctrly({
    closeOnScroll: true
});

trapFocus

Default: false

Passing true as an option ensures that TAB and SHIFT+TAB do not move focus outside the target.

Example

ctrly({
    trapFocus: true
});

allowMultiple

Default: false

By default, if a target becomes visible, all other open targets are closed. Passing true as an option allows multiple targets to be opened at the same time.

This can be combined with the context option to only allow multiple open targets inside a context element. See the accordion example for a use-case.

To allow multiple open targets, closeOnBlur must be set to false.

Example

ctrly({
    allowMultiple: true
});

on

Default: {}

Allows to define event callbacks as {event: callback} pairs.

Example

ctrly({
    on: {
        open: target => {
            // Called before a target is opened
        },
        opened: target => {
            // Called after a target has been opened
        },
        close: target => {
            // Called before a target is closed
        },
        closed: target => {
            // Called after a target has been closed
        }
    }
});

More information about the event callbacks can be found in the Events section.

autoInit

Default: true

By default, initialization is done when calling ctrly(). Passing false as an option disables this behavior and the init() method must be called manually.

Example

const { init } = ctrly({
    autoInit: false
});

init();

Events

ctrly triggers several events when a target is opened or closed.

There are 2 ways to bind listeners to the events.

  1. Through the on option.
  2. Through DOM event listeners on the target element (the DOM event names are prefixed with ctrly:, eg. ctrly:open).

The following events are available.

open

Triggered before the target element is opened.

Example

ctrly({
    on: {
        open: target => {
            target.classList.add('is-opening');
        }
    }
});

// or

document.getElementById('my-target').addEventListener('ctrly:open', e => {
    const target = e.target;

    target.classList.add('is-opening');
});

opened

Triggered after the target element has been opened.

Example

ctrly({
    on: {
        opened: target => {
            target.classList.remove('is-opening');
        }
    }
});

// or

document.getElementById('my-target').addEventListener('ctrly:opened', e => {
    const target = e.target;

    target.classList.remove('is-opening');
});

close

Triggered before the target element is closed.

Example

ctrly({
    on: {
        close: target => {
            target.classList.add('is-closing');
        }
    }
});

// or

document.getElementById('my-target').addEventListener('ctrly:close', e => {
    const target = e.target;

    target.classList.add('is-closing');
});

closed

Triggered after the target element has been opened.

Example

ctrly({
    on: {
        closed: target => {
            target.classList.remove('is-closing');
        }
    }
});

// or

document.getElementById('my-target').addEventListener('ctrly:closed', e => {
    const target = e.target;

    target.classList.remove('is-closing');
});

Thank You

  • BrowserStack for providing free VMs for automated testing.
  • GitHub for providing free Git repository hosting.
  • npm for providing the package manager for JavaScript.
  • TravisCI for providing a free build server.

License

Copyright (c) 2018-2019 Jan Sorgalla. Released under the MIT license.