# Toggle Count

Toggle count from one value to another.

[![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/toggle-count) [![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/toggle-count.html)

## Contents

- [Overview](#overview)
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Configuration Options](#configuration-options)
- [JavaScript API](#javascript-api)
- [Common Patterns](#common-patterns)
- [License](#license)

## Overview

The Toggle Count component provides animated counting functionality that transitions between two numeric values. It's commonly used for pricing displays, statistics, or any scenario where values need to animate between states (e.g., monthly/annual pricing).

**Key Features:**
- Animated counting between values
- Configurable animation duration
- Programmatic control via JavaScript API
- Smooth transitions
- Support for multiple count elements

## Installation

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

```bash
npm i @preline/toggle-count
```

### CSS

[`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS file into your Tailwind CSS file.

```css
@import "tailwindcss";

/* @preline/toggle-count */
@import "./node_modules/@preline/toggle-count/theme.css";
```

### JavaScript

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

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

  new HSToggleCount(document.querySelector("#toggle-count"));
</script>
```

### Via Bundler

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

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

```js
import "@preline/toggle-count";
```

`@preline/toggle-count/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 HSToggleCount from "@preline/toggle-count/non-auto";

HSToggleCount.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#toggle-count");
if (el) new HSToggleCount(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 toggle count component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The count animates between min and max values when the toggle changes.

```html
<div>
  <div id="hs-toggle-count-first">
    <label>
      Monthly
      <input id="hs-toggle-count-monthly-first" name="hs-toggle-count-first" type="radio" class="hidden">
    </label>
    <label>
      Annual
      <input id="hs-toggle-count-annual-first" name="hs-toggle-count-first" type="radio" class="hidden" checked/>
    </label>
  </div>
</div>

<div class="space-x-5">
  <span data-hs-toggle-count='{
    "target": "#hs-toggle-count-first",
    "min": 19,
    "max": 29
  }'>
    19
  </span>
  <span data-hs-toggle-count='{
    "target": "#hs-toggle-count-first",
    "min": 89,
    "max": 99
  }'>
    89
  </span>
  <span data-hs-toggle-count='{
    "target": "#hs-toggle-count-first",
    "min": 129,
    "max": 149
  }'>
    129
  </span>
</div>
```

**Structure Requirements:**
- `data-hs-toggle-count`: Required on the element that displays the count, contains configuration options as JSON
- `:target`: Required, must be a valid CSS selector pointing to the toggle element (radio buttons or checkbox)
- Toggle element (radio buttons or checkbox) that triggers the count change
- Multiple count elements can share the same target

**Initial State:**
- Count displays the `min` value initially
- When toggle changes, count animates to `max` value

## Configuration Options

### Data Options

Data options are specified in the `data-hs-toggle-count` attribute as a JSON object.

| Option | Target Element | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `data-hs-toggle-count` | Count display element | - | - | Activate a Toggle Count by specifying on an element. Should be added to the container. |
| `:target` | Inside `data-hs-toggle-count` | string (CSS selector) | - | Determines which element will be observed. This must be a valid selector pointing to the toggle element (radio buttons or checkbox). Required. |
| `:min` | Inside `data-hs-toggle-count` | number | `0` | Specifies default number (starting value). |
| `:max` | Inside `data-hs-toggle-count` | number | `0` | Specifies the number to which the count up will go (ending value). |
| `:duration` | Inside `data-hs-toggle-count` | number | `700` | Counting speed (animation duration in milliseconds). |

**Example:**
```html
<span data-hs-toggle-count='{
  "target": "#hs-toggle",
  "min": 10,
  "max": 50,
  "duration": 1000
}'>
  10
</span>
```

## JavaScript API

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

### Instance Methods

These methods are called on a toggle count instance.

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `countUp()` | None | `void` | Force count up animation. Animates from `min` to `max` value. |
| `countDown()` | None | `void` | Force count down animation. Animates from `max` to `min` value. |
| `destroy()` | None | `void` | Destroys the toggle count instance, removes all generated markup, classes, and event listeners. Use when removing toggle count from DOM. |

### Static Methods

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

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `HSToggleCount.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HSToggleCount \| { id: string \| number, element: HSToggleCount } \| null` | Returns the toggle count instance associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSToggleCount` instance. If `isInstance` is `false` or omitted, returns the `HSToggleCount` instance directly. Returns `null` if toggle count instance is not found. |

### Usage Examples

**Example 1: Force count up**
```javascript
// Get the toggle count instance
const instance = HSToggleCount.getInstance('#hs-toggle-count', true);

if (instance) {
  const { element } = instance;
  const countUpBtn = document.querySelector('#hs-count-up-btn');

  countUpBtn.addEventListener('click', () => {
    element.countUp();
  });
}
```

**Example 2: Force count down**
```javascript
const instance = HSToggleCount.getInstance('#hs-toggle-count', true);

if (instance) {
  const { element } = element;
  const countDownBtn = document.querySelector('#hs-count-down-btn');

  countDownBtn.addEventListener('click', () => {
    element.countDown();
  });
}
```

**Example 3: Getting instance and accessing properties**
```javascript
// Get the toggle count instance
const instance = HSToggleCount.getInstance('#hs-toggle-count', true);

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

  // Access instance properties
  console.log('Min value:', element.min);
  console.log('Max value:', element.max);
  console.log('Duration:', element.duration);
  console.log('Is checked:', element.isChecked);

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

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

## Common Patterns

### Pattern 1: Pricing Toggle

Toggle between monthly and annual pricing.

```html
<div id="hs-pricing-toggle">
  <input type="radio" name="pricing" id="monthly" checked>
  <input type="radio" name="pricing" id="annual">
</div>

<span data-hs-toggle-count='{
  "target": "#hs-pricing-toggle",
  "min": 19,
  "max": 199
}'>
  $19
</span>
```

### Pattern 2: Custom Duration

Set custom animation duration.

```html
<span data-hs-toggle-count='{
  "target": "#hs-toggle",
  "min": 0,
  "max": 100,
  "duration": 2000
}'>
  0
</span>
```

## License

Copyright (c) 2026 Preline Labs.

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