flexcord
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

flexcord

Build Status NPM Version

NAME

flexcord - flexible ARIA-first accordions which work with your existing CSS, markup, and code

INSTALLATION

$ npm install flexcord

SYNOPSIS

JavaScript

import { Accordion, MultiAccordion } from 'flexcord'
 
for (const el of document.querySelectorAll('.accordion')) {
    const klass = el.hasAttribute('data-multi-select') ? MultiAccordion : Accordion
    klass.mount(el, options)
}

CSS

/* hide closed panels (the default) */
.accordion [aria-hidden="true"] {
    display: none;
}

HTML

before:

<div class="accordion">
    <div role="heading">
        <button aria-controls="foo-panel">Foo</button>
    </div>
    <section id="foo-panel">...</section>
 
    <div role="heading">
        <button aria-controls="bar-panel" aria-expanded="true">Bar</button>
    </div>
    <section id="bar-panel">...</section>
 
    <div role="heading">
        <button aria-controls="baz-panel">Baz</button>
    </div>
    <section id="baz-panel">...</section>
</div>

after:

<div role="presentation" class="accordion">
    <div role="heading">
        <button
            id="header-abc"
            aria-controls="foo-panel"
            aria-expanded="false">Foo</button>
    </div>
    <section
        id="foo-panel"
        role="region"
        aria-labelledby="header-abc"
        aria-hidden="true">...</section>
 
    <div role="heading">
        <button
            id="header-def"
            aria-controls="bar-panel"
            aria-expanded="true">Bar</button>
    </div>
    <section
        id="bar-panel"
        role="region"
        aria-labelledby="header-def"
        aria-hidden="false">...</section>
 
    <div role="heading">
        <button
            id="header-ghi"
            aria-controls="baz-panel"
            aria-expanded="false">Baz</button>
    </div>
    <section
        id="baz-panel"
        role="region"
        aria-labelledby="header-ghi"
        aria-hidden="true">...</section>
</div>

DESCRIPTION

flexcord is a library which implements flexible, ARIA-first accordions which work with your markup, CSS and code rather than the other way round.

WHY?

There are many accordion implementations on NPM, but most of them bake into their APIs the specific use case for which they were conceived, usually in the form of classes and/or data attributes that must be defined in the HTML and overridden in the CSS to take advantage of their functionality.

This makes them perfect for anyone who has exactly the same use case, and inconvenient for anyone who doesn't. flexcord is designed to adapt to the conventions your app or framework already uses, while also supporting zero-configuration usage out of the box by leveraging the conventions established in the WAI-ARIA accordion design-pattern.

TERMINOLOGY

The following terms are used in the description below:

header

A header-like element (e.g. H1, H2 etc.) which typically contains a button-like element which triggers the opening/closing of its corresponding accordion panel.

button

A clickable element within a header which triggers the opening/closing of its corresponding accordion panel.

panel

A section which is displayed when an accordion header is activated/expanded and hidden when it is de-activated/collapsed.

TYPES

The following types are referenced in the descriptions below:

AccordionItem

An object representing a header/panel pair in an accordion:

type AccordionItem = {
    accordion: HTMLElement;
    button: HTMLElement;
    header: HTMLElement;
    index: number;
    isOpen: boolean;
    panel: HTMLElement;
}

Options

Optional hooks to configure an accordion's HTML bindings and behavior.

type Options = {
    header?: string | (accordion: HTMLElement) => Iterable<HTMLElement>;
    button?: string | ({ accordion: HTMLElement, header: HTMLElement }) => HTMLElement;
    disabled?: (item: AccordionItem, next: () => boolean) => boolean;
    panel?: ({ accordion: HTMLElement, button: HTMLElement, header: HTMLElement }) => HTMLElement;
}

EXPORTS

Accordion

An accordion in which no more than one panel can be open at a time.

METHODS

Accordion.mount

Type: (el: HTMLElement, options?: Options) → Accordion

An alternative way to call the accordion class's constructor i.e.:

Accordion.mount(el, options)

is equivalent to:

new Accordion(el, options)

close

Type: () → this

Closes the currently open panel, if any.

Type: (index: number) → this

Closes the panel at the specified (0-based) index.

open

Type: (index: number) → this

Opens the panel at the specified (0-based) index.

toggle

Type: (index: number, open?: boolean) → this

Toggles the panel at the specified (0-based) index i.e. opens it if it's closed or closes it if it's open. Can take an optional boolean state to set the panel to.

MultiAccordion

An accordion in which mupltiple panels can be open at the same time.

METHODS

MultiAccordion.mount

Type: (el: HTMLElement, options?: Options) → MultiAccordion

An alternative way to call the accordion class's constructor. See Accordion.mount for more details.

close

Type: () → this

Closes all open panels.

Type: (index: number) → this

Closes the panel at the specified (0-based) index.

Type: (index: Array<number>) → this

Closes the panel at the specified (0-based) indices.

open

Type: () → this

Opens all open panels.

Type: (index: number) → this

Opens the panel at the specified (0-based) index.

Type: (index: Array<number>) → this

Opens the panel at the specified (0-based) indices.

toggle

Type: () → this

Toggles the open state of all panels i.e. opens all closed panels and closes all open panels.

Type: (index: number) → this

Toggles the open state of the panel at the specified (0-based) index.

Type: (indices: Array<number>) → this

Toggles the open state of the panels at the specified (0-based) indices.

Options

The constructor takes an optional Options object with the following (optional) fields.

header

Type: string | (accordion: HTMLElement) → Iterable<HTMLElement>
Default: "[role='heading']"

A selector which returns a collection (e.g. NodeList, Array, jQuery instance etc.) of DOM elements representing the header-like elements inside the accordion. Headers are elements which contain (or are) an element which triggers the opening/closing of the corresponding panel.

The default value matches elements with a heading role.

If supplied as a string, it is interepeted as a CSS3 selector and converted into a function which returns a NodeList resulting from the evaluation of the selector against the accordion with querySelectorAll.

button

Type: string | ({ accordion: HTMLElement, header: HTMLElement }) → HTMLElement
Default: "[aria-controls]"

A selector (string) or function which returns an element in the header which functions like a button. An onclick event handler is attached to this element which triggers the opening/closing of the associated panel.

The default value selects the first element in the header with a non-empty aria-controls attribute.

Typically, the button element is the child/descendant of an element which functions like a header element (e.g. H1, H2 etc.). By default, this is an element with a heading role e.g.:

<div class="accordion">
    <div role="heading">
        <button aria-controls="foo-panel">Foo</button>
    </div>
    <section id="foo-panel">...</section>
 
    <div role="heading">
        <button aria-controls="bar-panel">Bar</button>
    </div>
    <section id="bar-panel">...</section>
</div>

- but they can easily be the same element if a suitable selector is supplied e.g.:

<div class="accordion">
    <button aria-controls="foo-panel">Foo</button>
    <section id="foo-panel">...</section>
 
    <button aria-controls="bar-panel">Bar</button>
    <section id="bar-panel">...</section>
</div>
Accordion.mount(el, {
    header: '[aria-controls]',
    button: ({ accordion, header }) => header,
})

disabled

Type: (item: AccordionItem, next: () → boolean) → boolean

A callback used to determine whether an item is disabled. Disabled items don't respond to open or close (or toggle) actions.

The next parameter is a function which calls the default disabled implementation with the same AccordionItem object. The default implementation returns true if the item's button element has an aria-disabled="true" attribute, or false otherwise.

Can be used e.g. to avoid opening/closing items with a disabled button:

// disable <button disabled>...</button> as well as <button aria-disabled="true">...</button>
function disabled ({ button }, next) {
    return button.hasAttribute('disabled') || next()
}
 
const accordion = new Accordion(el, { disabled })

- or to disable every item in an accordion:

<div class="accordion" data-disabled="true">
    ...
</div>
function disabled ({ accordion }) {
    return accordion.getAttribute('data-disabled') === 'true'
}
 
const accordion = new Accordion(el, { disabled })

panel

Type: string | ({ accordion: HTMLElement, button: HTMLElement, header: HTMLElement }) → HTMLElement

The container of the content to display/hide when the corresponding header is activated/de-activated.

The default value is a function which selects the element whose ID corresponds to the button's aria-controls ID.

Events

Accordions implement the EventEmitter interface and support the following events.

before:change

Type: (item: AccordionItem, type: string, accordion: Accordion) → void

Fired after a button is clicked and before its corresponding panel is opened or closed. Passed the action (i.e. "open" or "close") as a parameter.

before:close

Type: (item: AccordionItem, accordion: Accordion) → void

Fired after a button is clicked and before its corresponding panel is closed.

before:open

Type: (item: AccordionItem, accordion: Accordion) → void

Fired after a button is clicked and before its corresponding panel is opened.

change

Type: (item: AccordionItem, type: string, accordion: Accordion) → void

Fired after a panel is opened or closed. Passed the action (i.e. "open" or "close") as a parameter.

close

Type: (item: AccordionItem, accordion: Accordion) → void

Fired after a panel is closed.

open

Type: (item: AccordionItem, accordion: Accordion) → void

Fired after a panel is opened.

DEVELOPMENT

NPM Scripts

The following NPM scripts are available:

  • build - compile and bundle the library for testing and release
  • clean - remove temporary files and build artifacts
  • test - run the test suite

COMPATIBILITY

  • > 1% of browsers
  • IE 11
  • not Opera Mini

SEE ALSO

VERSION

0.1.1

AUTHOR

chocolateboy

COPYRIGHT AND LICENSE

Copyright © 2018-2019 by chocolateboy.

This is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.

Package Sidebar

Install

npm i flexcord

Weekly Downloads

3

Version

0.1.1

License

Artistic-2.0

Unpacked Size

244 kB

Total Files

15

Last publish

Collaborators

  • chocolateboy