Giter Site home page Giter Site logo

michu2k / accordion Goto Github PK

View Code? Open in Web Editor NEW
340.0 3.0 75.0 1.72 MB

Accordion module created in pure javascript & CSS. Very useful to create FAQ lists on your website.

Home Page: https://michu2k.github.io/Accordion/

License: MIT License

HTML 5.99% JavaScript 87.54% SCSS 6.47%
javascript accordion es6 accessibility aria javascript-library a11y

accordion's Introduction

Accordion

Lightweight and accessible accordion module with an extensible API. With the module you can create accordion on your website, useful especially for creating FAQ lists.

Version

3.3.4

Installation

npm

Install the package & import files

npm install accordion-js
import Accordion from 'accordion-js';
import 'accordion-js/dist/accordion.min.css';
CDN

Include files using CDN.

https://unpkg.com/[email protected]/dist/accordion.min.css
https://unpkg.com/[email protected]/dist/accordion.min.js
<link rel="stylesheet" href="[CDN CSS URL]">
<script src="[CDN JS URL]"></script>
Github

You can also download files from Github and attach them manually to your project.
Note: On production use files (JS and CSS) only from dist/ folder.

Usage

Include files

See the section above.

Create HTML layout

This is just an example of a layout. You can create your own HTML structure.

<div class="accordion-container">
  <div class="ac">
    <h2 class="ac-header">
      <button type="button" class="ac-trigger">Lorem ipsum dolor sit amet.</button>
    </h2>
    <div class="ac-panel">
      <p class="ac-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
    </div>
  </div>

  <div class="ac">
    <h2 class="ac-header">
      <button type="button" class="ac-trigger">Lorem ipsum dolor sit amet.</button>
    </h2>
    <div class="ac-panel">
      <p class="ac-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
    </div>
  </div>

  <div class="ac">
    <h2 class="ac-header">
      <button type="button" class="ac-trigger">Lorem ipsum dolor sit amet.</button>
    </h2>
    <div class="ac-panel">
      <p class="ac-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
    </div>
  </div>
</div>
Initialize the module
<script>
  new Accordion('.accordion-container');
</script>

API

Examples

new Accordion(container, options)

  • container - string | HTMLElement (required), selector of accordion container
  • options - object (optional), accordion options
// Default options
new Accordion('.container-first');

// User options
new Accordion('.container-second', {
  duration: 400,
  showMultiple: true,
  onOpen: function(currentElement) {
    console.log(currentElement);
  }
});

// Define several accordions with the same options (pass an array with selectors)
new Accordion(['.container-first', '.container-second'], {});

// or pass an array with HTMLElements
const accordions = Array.from(document.querySelectorAll('.accordion-container'));
new Accordion(accordions, {});

// Detach events
const accordion = new Accordion('.container-first');
accordion.detachEvents();
Options
Option Type Default value Description
duration number 600 Animation duration in ms
ariaEnabled boolean true Add ARIA elements to the HTML structure
collapse boolean true Allow collapse expanded panel
showMultiple boolean false Show multiple elements at the same time
onlyChildNodes boolean true Disabling this option will find all items in the container. Warning: Setting to false will break the functionality of nested accordions
openOnInit array [] Show accordion elements during initialization
elementClass string 'ac' Element class
triggerClass string 'ac-trigger' Trigger class
panelClass string 'ac-panel' Panel class
activeClass string 'is-active' Active element class
beforeOpen function - Calls before the item is opened.
beforeOpen: (currElement) => {}
onOpen function - Calls when the item is opened.
onOpen: (currElement) => {}
beforeClose function - Calls before the item is closed.
beforeClose: (currElement) => {}
onClose function - Calls when the item is closed.
onClose: (currElement) => {}
Methods
Option Description Arguments
attachEvents() Attach events -
detachEvents() Detach events -
open() Open the accordion element with the given idx
E.g. acc.open(1)
idx - element index
close() Close the accordion element with the given idx
E.g. acc.close(1)
idx - element index
toggle() Toggle the accordion element with the given idx
E.g. acc.toggle(1)
idx - element index
openAll() Open all accordion elements (without animation) -
closeAll() Close all accordion elements (without animation) -
update() If there are new items added by lazy load, you can run this method to update the Accordion -
destroy() Destroy accordion instance:
Open elements, remove events, IDs & ARIA
-

v3 Release Info

There have been a lot of changes to the API in version 3.0.0, so if you are using previous versions of the accordion (2.8.0 and below), I recommend updating the package to the latest version with new structure and options.

accordion's People

Contributors

dependabot[bot] avatar janmarkuslanger avatar michu2k avatar pustur avatar tristanag avatar xemlock avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

accordion's Issues

Nested accordions

Is there a way to nest an accordion into another one with v3 ?

Such as :

Primary Accordion

  • Choice 1
    -- Content
  • Choice 2
    -- SubChoice 1
    --- Content
    -- SubChoice 2
    --- Content

Existing id attributes are overwritten

id attributes already present before the Accordion is attached should be reused, not overwritten, and similarly, not removed when the accordion is detached.

Related to #28

Anchor scrolling with predefined IDs not possible

This is a great accordion js and I've been very happy utilizing it on my project, until I needed a feature to predefine unique id's on the accordion item markups itself, the purpose is so that hash anchor names still makes sense content-wise in the case of anchor scrolling (scroll to and open accordion based on hash anchor id), but this library auto generating unique ids using incremental number prefixed by "accordion", I know that is to make each instances unique, but hash anchor id needs to be content related as well

Is there a way to achieve content specific id's on each accordion item? that I could define the id myself and not have the js library change it?

Class names are not escaped in selectors

This makes the accordion unusable with custom class names (e.g. when using separate classes for behavior and for look) containing special characters, such as : (e.g. js:accordion-element).

This is caused by using the same unescaped class names in querySelectorAll() and classList.contains(). So either class names should be escaped, or classList.contains() should be replaced with element.matches(selector) for consistent behavior.

Ideally CSS.escape() should be used for this, however old browsers may need a polyfill for it to work (so this would be a breaking change).

using an anchor as a trigger not possible

I have been having trouble using an anchor tag as a trigger.
The use case for this is I have 5-10 frequently asked questions and i would like to have anchors to each question and also a mechanism to scroll to the correct question if the url contains a hash parameter.

In the past (using bootstrap3) this was possible and I simply return false or event.preventdefault on the anchor allow the accordion override the anchor functionality.

I have worked around it by wrapping my anchor with another div and using that as a trigger and using css to prevent clicks on anchor tag obscuring/intercepting the wrapping trigger event listener but this is not ideal.

Another issue I noticed is when I initialize the accordion to have a specific question open, via the openOnInit parameter, it does not fire the onOpen or beforeOpen event which I was relying on to begin the scroll down the page.

I have been able to work around both issues but it would be nice to have better support on those two features built in.
Thanks for your time and thanks for this great accordion script.

Active State after 'openOnInit'

I'm passing the option: openOnInit: [2] in order to show the third accordion item expanded by default, but its corresponding header/button's style remains in collapsed state.

How can I make the header style change accordingly to expanded state when using openOnInit: []?

Incorrect state of third header after being triggered by openOnInit: [2]:
Screen Shot 2023-02-21 at 10 58 21 AM

Correct state of third header after being triggered by user click:
Screen Shot 2023-02-21 at 10 58 28 AM

Adding/removing an attribute from the button + edit the general structure

Hi!

I noticed that in your solution, the button does not have the type attribute with the button value. This is not quite correct because by default the button tries to send data to the server because the type attribute with the value submit is set. I recommend redefining this by adding the following to the button — type="button".

I also don't quite understand why the role attribute with the button value is set to the button. The button is calculated with this value by default. It's just redundant code.

Another point about the structure of the accordion itself. You have it made with the help of tags — div. But in terms of accessibility, this is not the best option. It is best to do this with a list — ul > li. Since when a person starts the screen reader, he will be told — “This is a list with a certain number of elements.”

I would also recommend replacing the h2 header with h3. Because it often happens that h2 is used as the header of some section.

And so, in general, the accordion turned out to be really cool! At least I am glad that this is not another solution using jQuery. :)

Is there any way to target an accordion by ID?

I have dynamic accordions being created on the page and would love to target them from outside the container but given the containers are also created multiple times, every index is 0....is there any way to target opening them based on ID or other attribute? Or open to other suggestions :)

An option to disable default styling.

I would like an option to disable the default styling of the accordion. I just want this package to facilitate the collapsing and opening. I want to be able to style the elements freely.

Cleanup function

Can you add a destroy method that removes all listeners so that this doesnt leave open memory for SPA applications.

var accordion = new Accordion('.accordion-container');
accordion.destroy(); // cleans up all memory and events

Links within accordion content don't open

If I insert a link (<a href="#">text</a>) within the accordion content itself, then the links don't open. I can replicate this issue with the index.html file included in the zip file, by adding a link in the accordion content (<div class="ac-a">)

onClose is triggered on all ancestors of a closed panel

onClose is triggered on all ancestors of a closed panel, but should only be triggered on the closed panel itself.

Using nested example from https://michu2k.github.io/Accordion/:

new Accordion(['.nested-accordion-parent', '.nested-accordion-child'], {
  onClose: (el) => console.log('onClose',el)
}

after closing "Nested 1" accordion we get the following in the browser console:

onClose <div class=​"ac js-enabled" id=​"ac-5">​…​</div>​
onClose <div class=​"ac js-enabled is-active" id=​"ac-4">​…​</div>

The second onClose shouln't be executed, because the parent panel is still open.

Responsive initialization

Would it be possible to add a setting for responsive initialization depending on viewport (or container) width? Something like

new Accordion('.accordion-container', {
  responsive: {
    operator: '<',
    viewPort: 640
  }
});

or

new Accordion('.accordion-container', {
  responsive: {
    operator: '>=',
    viewPort: 1024
  }
});

or similar which would init the accordion for screen size < 640px or >= 1024px. That way you could have, for example, the accordion active only for mobile screens where you have limited screen space, but not on desktop, or vice versa.

I tried to implement something like this with resizeObserver by initializing the Accordion if container width is less than n px and destroy() if wider, but I couldn't quite figure out how to get it working properly.

method Update

After applying the Update method, the first loaded element opens. Is this the expected behavior?

Several accordions in one

Hello! How can I put several accordions in one. Now when you click on the nested accordions, the main accordion closes, this should not be.

Prevent accordion content from being tabbable when closed

Nice little lightweight library you've got here.

For accessibility reasons, a site should be keyboard navigable. One thing I'm thinking about is how to prevent the contents of closed accordion panels from being accessible via the tab key. This includes links, buttons, youtube embeds etc.

Then once the accordion panel is open, the user should be able to tab through everything as normal.

One solution would be to loop through all the children elements and set tabindex="-1", special consideration would need to be made for iframe contents (youtube embeds). Opening the panel would need to reverse this.

Another cleaner solution might be to set the content of each accordion panel to display:none; until it's open. This would mess with the current system for gaging the height and thus the opening animation, however, there should be ways around this.

I'd be curious to know your thoughts.

openOnInit example

I'm wondering if you can provide an example of how one might use the openOnInit option please?

I'm curious if this option allows a designated item to be open on initialization? If that is the case then I'm doubly interested in how your example would look.

I've tried getting the openOnInit to work as I understood, but coming up with empty. Here is something I'm working with:

import Accordion from 'accordion-js';

/**
 * @module Accordion
 *
 * @description
 *
 * Accordion
 *
 */
export default class Accordions {
	/**
	 * Initialize everything
	 */
	constructor() {
		// Grab all accordions.
		this.accordions = Array.from( document.querySelectorAll( '.accordion-container' ) );

		if ( ! this.accordions.length ) {
			return;
		}

		new Accordion( this.accordions, {
			openOnInit: [ '1' ],
		} );
	}
}

Thanks for writing and maintaining this handy component.

Accordions not expanding consistently (on mobile)

Hello, I've been trying to get this to work for a while now, the accordions are only active on mobile (I manually copied the accordion-js css file and wrapped everything in a media query), but using the responsive mode on a browser, I cannot open the accordions, and on mobile, they stop working if you scroll upwards and press an accordion, like they get clicked twice at the same time

The page in question

The only active setting for the accordions is showMultiple: true

Issues with `closeAll()` method

When using the closeAll() method on an existing accordion, I'm noticing a couple of issues:

  1. A previously-registered onClose function on the accordion doesn't fire.
  2. The close transition for any open accordion folds doesn't happen, and the open fold just disappears instantly.

Both of these issues do not occur if I close a specific fold like close(0), but only with closeAll().

Incorrect animation height when using beforeOpen to lazyLoad Content

I want to use beforeOpen to lazy load the content of my accordion. Lazy loading works, but the animation is wrong. Unfortunately, in your method showElement the height of the container (=how large it should be after onOpen) is calculated before the callback beforeOpen is run. (By lazy loading the content, the height changes.) That is why the accordion is not animating to the correct height. (In my example it is animating from hidden to 0px even though I add content in showElement.)

I think the cause of the bug is here:

Accordion/src/accordion.js

Lines 249 to 252 in de54532

const height = panel.scrollHeight;
element.classList.add(activeClass);
if (calcHeight) beforeOpen(element);

You can see the bug at: https://codepen.io/jonpfote/pen/WNzKoLm (I tested the bug with Chrome and Firefox)

I would like the order to be:

  1. call beforeOpen function (There I want to load and add the content to .ac-panel)
  2. calculate 'height' of content (for animation)
  3. start animation

Currently, the order is 2 -> 1 -> 3. That means beforeOpen can't be used to lazy load the content. (if the height of the container changes)

I tried to call accordion.update() in my beforeOpen function, but this does not solve the issue

Please tell me if I missed something. (For example, if there is another way to lazy load content)

Object doesn't support property or method 'forEach'

Hi there! first off all many thanks for creating this plugin. It helped me a lot. However, the js doesn't work on IE because of an error: "Object doesn't support property or method 'forEach'" really appreciate your help. Thanks!

Any way to move the icon to the left?

Its working great! I just want to move the icon to the left.
image
I tried using ::before instead of ::after. I doesnt seem to work like that.
Other than that It could be done with using flexbox to move it around. But then I would have to make the icon an img tag
This breaks the changing icon when opened or closed.
image
image

This is an example of what im doing right now.(I replaced the + and - with Fontawesome Unicode Icons)
Im sorry if this question seems stupid.
Thanks for any help!

Close accordion by clicking element outside the questionClass?

I have an element inside the answerClass (an "X") which, when clicked, I would like to close that accordion. Is this possible?

I am getting an error in console accordion.min.js?ver=2.8.0:9 Uncaught TypeError: t.className.match is not a function when clicking this element after applying the targetClass

Remove constraint that accordion items must be direct children of the accordion container

Hey, sorry to bother you again.

I run into a problem with this layout:

layout

Basically I need to separate the accordion into columns, but the accordion should still work as one piece.

I found that inserting an elment between the container .accordion-container and the items .ac breaks the accordion functionality.

JSFiddle to show the problem

My proposal would be to allow the user to define a selector to target the items, something like this:

new Accordion('.accordion-container', {
  // Feature proposal
  childrenSelector: '.ac'
});

What do you think? Is it doable?

Thanks for your time,
Loris

EDIT: or maybe we could use the value of elementClass to target the children? Just sharing some ideas.

EDIT2: I made some changes in my fork:

you can take a look and if you want I can submit them as pull requests :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.