# Collapse

Toggle the visibility of content.

[![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/collapse) [![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/collapse.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 Collapse component allows you to show and hide content with smooth transitions. It's a simple, lightweight solution for creating expandable/collapsible sections without the complexity of accordion groups.

**Key Features:**
- Simple show/hide functionality
- Smooth CSS transitions
- Programmatic control via JavaScript API
- Event system for lifecycle hooks
- Accessibility attributes (ARIA) built-in

## Installation

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

```bash
npm i @preline/collapse
```

### 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/collapse */
@source "../node_modules/@preline/collapse/*.js";
@import "./node_modules/@preline/collapse/variants.css";
@import "./node_modules/@preline/collapse/theme.css";
```

### JavaScript

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

```html
<script src="./node_modules/@preline/collapse/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 HSCollapse from "@preline/collapse/non-auto.mjs";

  new HSCollapse(document.querySelector("#collapse"));
</script>
```

### Via Bundler

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

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

```js
import "@preline/collapse";
```

`@preline/collapse/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 HSCollapse from "@preline/collapse/non-auto";

HSCollapse.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#collapse");
if (el) new HSCollapse(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 a collapse component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The content is hidden by default and expands when the button is clicked.

```html
<button type="button" class="hs-collapse-toggle" id="hs-unstyled-collapse" aria-expanded="false" aria-controls="hs-unstyled-collapse-heading" data-hs-collapse="#hs-unstyled-collapse-heading" role="region">
  Collapse
</button>
<div id="hs-unstyled-collapse-heading" class="hs-collapse hidden w-full overflow-hidden transition-[height] duration-300" aria-labelledby="hs-unstyled-collapse">
  This is a collapse body. The content expands and collapses when the toggle button is clicked, with smooth height transitions.
</div>
```

**Structure Requirements:**
- `hs-collapse-toggle`: Required button element that triggers the collapse
- `hs-collapse`: Required container for collapsible content
- `data-hs-collapse`: Required attribute on the toggle button, must be a valid CSS selector pointing to the collapse content
- Unique `id` attributes for the toggle button and collapse content
- Proper ARIA attributes (`aria-expanded`, `aria-controls`, `aria-labelledby`, `role="region"`)

**Initial State:**
- Set `aria-expanded="false"` on the toggle button initially
- Add `hidden` class to the collapse content initially
- Content visibility is controlled by the plugin

## Configuration Options

### Data Attributes

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

| Attribute | Target Element | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `data-hs-collapse` | `hs-collapse-toggle` (button) | string (CSS selector) | `null` | Collapse container selector. Must be a valid CSS selector pointing to the `hs-collapse` element. |

**Example:**
```html
<button data-hs-collapse="#hs-collapse-content">Toggle</button>
<div id="hs-collapse-content" class="hs-collapse hidden">Content</div>
```

### Required CSS Classes

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

| Class | Required On | Purpose |
| --- | --- | --- |
| `hs-collapse` | Content container | Identifies the collapsible content area |
| `hs-collapse-toggle` | Button element | The clickable element that expands/collapses content |

### Tailwind Modifiers

| Name | Description |
| --- | --- |
| `hs-collapse-open:*` | A modifier that allows you to set Tailwind classes when the collapse is open. |

## JavaScript API

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

### Instance Methods

These methods are called on a collapse instance.

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `show()` | None | `boolean` | Opens the collapsed content. Returns `false` if content is already open, `true` otherwise. |
| `hide()` | None | `boolean` | Collapses the currently open content. Returns `false` if content is already closed, `true` otherwise. |
| `destroy()` | None | `void` | Destroys the collapse instance, removes all generated markup, classes, and event listeners. Use when removing collapse from DOM. |

### Static Methods

These methods are called directly on the `HSCollapse` class.

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `HSCollapse.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HTMLElement \| { id: string \| number, element: HSCollapse } \| null` | Returns the collapse instance or element associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSCollapse` instance. If `isInstance` is `false` or omitted, returns the DOM element (`HTMLElement`). Returns `null` if collapse instance is not found. |
| `HSCollapse.show(target)` | `target`: `HSCollapse \| HTMLElement \| string` (CSS selector) | `void` | Shows the collapse content identified by target. Accepts a collapse instance, DOM element, or CSS selector string. Static alternative to instance `show()` method. |
| `HSCollapse.hide(target)` | `target`: `HSCollapse \| HTMLElement \| string` (CSS selector) | `void` | Hides the collapse content identified by target. Accepts a collapse instance, DOM element, or CSS selector string. Static alternative to instance `hide()` method. |

### Usage Examples

**Example 1: Using instance methods (public API)**
```javascript
// Create a new collapse instance
const collapse = new HSCollapse(document.querySelector('#hs-collapse'));
const showBtn = document.querySelector('#hs-show-btn');

// Show collapse programmatically
showBtn.addEventListener('click', () => {
  collapse.show();
});
```

**Example 2: Using static methods**
```javascript
const showBtn = document.querySelector('#hs-show-btn');

// Show collapse using static method (no instance needed)
showBtn.addEventListener('click', () => {
  HSCollapse.show('#hs-collapse');
});
```

**Example 3: Getting instance and using methods (recommended pattern)**
```javascript
// Get the collapse instance
const instance = HSCollapse.getInstance('#hs-collapse', true);

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

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

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

**Example 4: Destroying collapse instance**
```javascript
const instance = HSCollapse.getInstance('#hs-collapse', 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-collapse').remove();
  });
}
```

## Events

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

| Event Name | When Fired | Callback Parameter | Description |
| --- | --- | --- | --- |
| `on:open` | After collapse content is opened | `HTMLElement` (collapse element) | Fires after the collapse content has been displayed. Use for post-open actions like loading content. |
| `on:hide` | After collapse content is closed | `HTMLElement` (collapse element) | Fires after the collapse content has been hidden. Use for cleanup or state updates. |

### Event Usage Example

```javascript
// Get collapse instance
const instance = HSCollapse.getInstance('#hs-collapse', true);

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

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

  // Listen to hide event
  element.on('hide', (collapseElement) => {
    console.log('Collapse closed:', collapseElement);
    // Perform cleanup or state updates
  });
}
```

## Common Patterns

### Pattern 1: Programmatic Control

Control collapse from external buttons.

```html
<button class="hs-collapse-toggle" data-hs-collapse="#hs-collapse-content">Toggle</button>
<div id="hs-collapse-content" class="hs-collapse hidden">Content</div>

<button id="hs-show-collapse">Show</button>
<button id="hs-hide-collapse">Hide</button>

<script>
  const instance = HSCollapse.getInstance('#hs-collapse-content', true);
  if (instance) {
    const { element } = instance;

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

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

## License

Copyright (c) 2024 Htmlstream.

Licensed under the [MIT License](https://opensource.org/licenses/MIT).
