npm.io
5.0.0 • Published yesterday

@preline/accordion

Licence
Licensed under MIT and Preline UI Fair Use License
Version
5.0.0
Deps
0
Size
88 kB
Vulns
0
Weekly
0
Stars
6.4K

Accordion

Build vertically collapsing accordions in combination with Accordion JavaScript plugin.

npm License: MIT Demo

Contents

Overview

The Accordion component allows you to create collapsible content sections that can be expanded or collapsed by clicking on toggle buttons. It supports multiple accordion items within a group, with options for keeping items open, ensuring at least one item stays open, and treeview mode for hierarchical structures.

Key Features:

  • Multiple accordion items in a single group
  • Programmatic control via JavaScript API
  • Event system for lifecycle hooks
  • Treeview mode support
  • Accessibility attributes (ARIA) built-in

Installation

To get started, install Accordion plugin via npm, else you can skip this step if you are already using Preline UI as a package.

npm i @preline/accordion
CSS

Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.

@import "tailwindcss";

/* @preline/accordion */
@source "../node_modules/@preline/accordion/*.js";
@import "./node_modules/@preline/accordion/variants.css";
@import "./node_modules/@preline/accordion/theme.css";
JavaScript

Include the JavaScript that powers the interactive elements near the end of your </body> tag:

<script src="./node_modules/@preline/accordion/index.js"></script>
Manual Initialization

Use the non-auto entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.

<script type="module">
  import HSAccordion from "@preline/accordion/non-auto.mjs";

  new HSAccordion(document.querySelector("#accordion"));
</script>
Via Bundler

When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.

@preline/accordion is the auto-init entry: it scans the DOM and initializes matching elements automatically.

import "@preline/accordion";

@preline/accordion/non-auto is the manual entry: use it when you want explicit control over when initialization happens, either via autoInit() or by creating a specific instance yourself.

import HSAccordion from "@preline/accordion/non-auto";

HSAccordion.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#accordion");
if (el) new HSAccordion(el);
TypeScript

This package ships with TypeScript type definitions. No additional @types/ package is needed.

Basic usage

The following example demonstrates the minimal HTML structure required for an accordion component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The example shows three accordion items within a group, with the first item open by default.

<div class="hs-accordion-group">
  <div class="hs-accordion active" id="hs-unstyled-heading-one">
    <button class="hs-accordion-toggle" aria-expanded="true" aria-controls="hs-unstyled-collapse-one">
      Accordion #1
    </button>
    <div id="hs-unstyled-collapse-one" class="hs-accordion-content overflow-hidden transition-[height] duration-300" role="region" aria-labelledby="hs-unstyled-heading-one">
      Accordion content that expands and collapses when the toggle button is clicked.
    </div>
  </div>

  <div class="hs-accordion" id="hs-unstyled-heading-two">
    <button class="hs-accordion-toggle" aria-expanded="false" aria-controls="hs-unstyled-collapse-two">
      Accordion #2
    </button>
    <div id="hs-unstyled-collapse-two" class="hs-accordion-content hidden overflow-hidden transition-[height] duration-300" role="region" aria-labelledby="hs-unstyled-heading-two">
      Accordion content that expands and collapses when the toggle button is clicked.
    </div>
  </div>

  <div class="hs-accordion" id="hs-unstyled-heading-three">
    <button class="hs-accordion-toggle" aria-expanded="false" aria-controls="hs-unstyled-collapse-three">
      Accordion #3
    </button>
    <div id="hs-unstyled-collapse-three" class="hs-accordion-content hidden overflow-hidden transition-[height] duration-300" role="region" aria-labelledby="hs-unstyled-heading-three">
      Accordion content that expands and collapses when the toggle button is clicked.
    </div>
  </div>
</div>

Structure Requirements:

  • hs-accordion-group: Required wrapper container for all accordion items
  • hs-accordion: Required container for each accordion item
  • hs-accordion-toggle: Required button element that triggers expand/collapse
  • hs-accordion-content: Required container for collapsible content
  • Unique id attributes for each accordion item and its content
  • Proper ARIA attributes (aria-expanded, aria-controls, aria-labelledby, role="region")

Initial State:

  • To have an accordion item open by default, add the active class to the hs-accordion element
  • For closed items, add the hidden class to the hs-accordion-content element

Configuration Options

Data Attributes

Data attributes are added directly to HTML elements to configure accordion behavior.

Attribute Target Element Type Default Description
data-hs-accordion-always-open hs-accordion-group boolean attribute false (absent) When present (boolean attribute), accordion items stay open when another item is opened. By default, opening one item closes others. Presence of attribute = true, absence = false.

Example:

<!-- Boolean attribute: presence = true, absence = false -->
<div class="hs-accordion-group" data-hs-accordion-always-open>
  <!-- Multiple items can be open simultaneously -->
</div>
CSS Classes (Modifiers)

CSS class modifiers use Tailwind-style syntax with -- prefix to control behavior.

Class Modifier Target Element Values Default Description
--stop-propagation:* hs-accordion-toggle "true" | "false" "false" When "true", interrupts event propagation when toggle button is clicked. Useful when accordion is nested inside clickable elements.
--keep-one-open:* hs-accordion-group "true" | "false" "false" When "true", ensures at least one accordion item remains open at all times. Prevents closing the last open item.

Example:

<div class="hs-accordion-group --keep-one-open:true">
  <!-- At least one item will always be open -->
</div>

<button class="hs-accordion-toggle --stop-propagation:true">
  <!-- Click event won't bubble up -->
</button>
Required CSS Classes

These classes define the structure and must be present for the accordion to function.

Class Required On Purpose
hs-accordion-group Container wrapper Groups multiple accordion items together
hs-accordion Each accordion item container Identifies an individual accordion item
hs-accordion-toggle Button element The clickable element that expands/collapses content
hs-accordion-content Content container The collapsible content area
Optional CSS Classes
Class Required On Purpose
hs-accordion-treeview-root Parent container When present, activates treeview mode for hierarchical accordion structures
hs-accordion-selectable Elements inside treeview When treeview mode is active, elements with this class become selectable

Treeview Mode Example:

<div class="hs-accordion-treeview-root">
  <div class="hs-accordion-group">
    <div class="hs-accordion">
      <button class="hs-accordion-toggle">Parent</button>
      <div class="hs-accordion-content">
        <div class="hs-accordion-selectable">Selectable item</div>
      </div>
    </div>
  </div>
</div>

JavaScript API

The HSAccordion object is available in the global window object after the plugin is loaded.

Instance Methods

These methods are called on an accordion instance.

Method Parameters Return Type Description
show() None boolean Opens the collapsed accordion item. Returns false if item is already open, true otherwise. If other items are open and always-open is not set, they will be closed.
hide() None boolean Collapses the currently open accordion item. Returns false if item is already closed or if keep-one-open is enabled and this is the last open item, true otherwise.
destroy() None void Destroys the accordion instance, removes all generated markup, classes, and event listeners. Use when removing accordion from DOM.
Static Methods

These methods are called directly on the HSAccordion class.

Method Parameters Return Type Description
HSAccordion.getInstance(target, isInstance) target: HTMLElement | string (CSS selector)
isInstance: boolean (optional)
{ id: string | number, element: HSAccordion } | HTMLElement | null Returns the accordion instance or element associated with the target. If isInstance is true, returns collection item object { id, element } where element is the HSAccordion instance. If isInstance is false or omitted, returns the DOM element (HTMLElement). Returns null if accordion instance is not found.
HSAccordion.show(target) target: HSAccordion | HTMLElement | string (CSS selector) void Opens the accordion item identified by target. Accepts an accordion instance, DOM element, or CSS selector string. Static alternative to instance show() method. Only opens if item is not already open.
HSAccordion.hide(target) target: HSAccordion | HTMLElement | string (CSS selector) void Closes the accordion item identified by target. Accepts an accordion instance, DOM element, or CSS selector string. Static alternative to instance hide() method. Only closes if item is open and keep-one-open allows it.
Usage Examples

Example 1: Using instance methods (public API)

// Create a new accordion instance
const accordion = new HSAccordion(document.querySelector('#hs-accordion'));
const showBtn = document.querySelector('#hs-show-btn');
const hideBtn = document.querySelector('#hs-hide-btn');

// Open accordion programmatically
showBtn.addEventListener('click', () => {
  accordion.show();
});

// Close accordion programmatically
hideBtn.addEventListener('click', () => {
  accordion.hide();
});

Example 2: Using static methods

const showBtn = document.querySelector('#hs-show-btn');
const hideBtn = document.querySelector('#hs-hide-btn');

// Open accordion using static method (no instance needed)
showBtn.addEventListener('click', () => {
  HSAccordion.show('#hs-accordion');
});

// Close accordion using static method
hideBtn.addEventListener('click', () => {
  HSAccordion.hide('#hs-accordion');
});

Example 3: Getting instance and using methods (recommended pattern)

// Get the accordion instance
const instance = HSAccordion.getInstance('#hs-accordion', true);

if (instance) {
  const { element } = instance; // element is the HSAccordion instance
  const showBtn = document.querySelector('#hs-show-btn');

  // Use instance methods
  showBtn.addEventListener('click', () => {
    element.show();
  });

  // Clean up when removing from DOM
  function removeAccordion() {
    element.destroy();
  }
}

Example 4: Destroying accordion instance

const instance = HSAccordion.getInstance('#hs-accordion', true);

if (instance) {
  const { element } = instance;
  const removeBtn = document.querySelector('#hs-remove-btn');

  removeBtn.addEventListener('click', () => {
    // Clean up before removing from DOM
    element.destroy();
    // Now safe to remove the element
    document.querySelector('#hs-accordion').remove();
  });
}

Events

Accordion instances emit events that can be listened to for lifecycle hooks and custom behavior.

Event Name When Fired Callback Parameter Description
on:beforeOpen Before accordion item opens HTMLElement (current accordion element) Fires immediately before the accordion item starts opening. Can be used to cancel or modify behavior.
on:open After accordion item opens HTMLElement (current accordion element) Fires after the accordion item has fully opened. Use for post-open actions like loading content.
on:beforeClose Before accordion item closes HTMLElement (current accordion element) Fires immediately before the accordion item starts closing. Can be used to cancel or modify behavior.
on:close After accordion item closes HTMLElement (current accordion element) Fires after the accordion item has fully closed. Use for cleanup or state updates.
Event Usage Example
// Get accordion instance
const instance = HSAccordion.getInstance('#hs-accordion', true);

if (instance) {
  const { element } = instance;

  // Listen to open event
  element.on('open', (accordionElement) => {
    console.log('Accordion opened:', accordionElement);
    // Perform actions after accordion opens
    // e.g., load content, update UI, track analytics
  });

  // Listen to close event
  element.on('close', (accordionElement) => {
    console.log('Accordion closed:', accordionElement);
    // Perform cleanup or state updates
  });

  // Listen to beforeOpen event (can be used to cancel)
  element.on('beforeOpen', (accordionElement) => {
    console.log('About to open:', accordionElement);
    // Can add conditional logic here
  });

  // Listen to beforeClose event (can be used to cancel)
  element.on('beforeClose', (accordionElement) => {
    console.log('About to close:', accordionElement);
    // Can add conditional logic here
  });
}

Common Patterns

Pattern 1: Multiple Open Items

Allow multiple accordion items to be open simultaneously.

<div class="hs-accordion-group" data-hs-accordion-always-open>
  <div class="hs-accordion" id="hs-item-first">
    <button class="hs-accordion-toggle">Item 1</button>
    <div class="hs-accordion-content hidden">Content 1</div>
  </div>

  <div class="hs-accordion" id="hs-item-second">
    <button class="hs-accordion-toggle">Item 2</button>
    <div class="hs-accordion-content hidden">Content 2</div>
  </div>
</div>
Pattern 2: Always Keep One Open

Ensure at least one item is always open.

<div class="hs-accordion-group --keep-one-open:true">
  <div class="hs-accordion active" id="hs-item-first">
    <button class="hs-accordion-toggle">Item 1</button>
    <div class="hs-accordion-content">Content 1</div>
  </div>
  
  <div class="hs-accordion" id="hs-item-second">
    <button class="hs-accordion-toggle">Item 2</button>
    <div class="hs-accordion-content hidden">Content 2</div>
  </div>
</div>
Pattern 3: Programmatic Control

Control accordion from external buttons.

<div class="hs-accordion-group">
  <div class="hs-accordion" id="hs-accordion-first">
    <button class="hs-accordion-toggle">Content</button>
    <div class="hs-accordion-content hidden">Content here</div>
  </div>
</div>

<button id="hs-open-all">Open All</button>
<button id="hs-close-all">Close All</button>

<script>
  const instance = HSAccordion.getInstance('#hs-accordion-first', true);

  if (instance) {
    const { element } = instance;

    document.querySelector('#hs-open-all').addEventListener('click', () => {
      element.show();
    });

    document.querySelector('#hs-close-all').addEventListener('click', () => {
      element.hide();
    });
  }
</script>

License

Copyright (c) 2024 Htmlstream.

Licensed under the MIT License.

Keywords