UNPKG

preline

Version:

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

433 lines (326 loc) 16.6 kB
# Accordion Build vertically collapsing accordions in combination with Accordion JavaScript plugin. [![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/accordion) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Demo](https://img.shields.io/badge/demo-online-brightgreen)](https://preline.co/plugins/accordion.html) ## Contents - [Overview](#overview) - [Installation](#installation) - [Basic usage](#basic-usage) - [Configuration Options](#configuration-options) - [JavaScript API](#javascript-api) - [Events](#events) - [Common Patterns](#common-patterns) - [License](#license) ## 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. ```bash npm i @preline/accordion ``` ### CSS Use [`@source`](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file. ```css @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: ```html <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. ```html <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. ```js 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. ```js 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. ```html <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:** ```html <!-- 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:** ```html <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:** ```html <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)<br>`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)** ```javascript // 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** ```javascript 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)** ```javascript // 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** ```javascript 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 ```javascript // 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. ```html <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. ```html <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. ```html <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) 2026 Preline Labs. Licensed under the [MIT License](https://opensource.org/licenses/MIT).