# Animate with Triggle — Simple Trigger-Based CSS Animation Control

![Vanilla JS](https://img.shields.io/badge/JS-Vanilla%20JS-brightgreen?style=for-the-badge)
![No Dependencies](https://img.shields.io/badge/Dependencies-None-lightgrey?style=for-the-badge)
![Optimized for Mobile](https://img.shields.io/badge/Mobile-Optimized-blue?style=for-the-badge)
[![NPM](https://img.shields.io/npm/v/triggle?style=for-the-badge&label=triggle)](https://www.npmjs.com/package/triggle)
[![Downloads](https://img.shields.io/npm/dt/triggle?style=for-the-badge)](https://www.npmjs.com/package/triggle)
![npm package size](https://img.shields.io/badge/npm%20size-15.6%20kB-blue?style=for-the-badge)
![minified size](https://img.shields.io/badge/minified--js-3.6%20kB-blue?style=for-the-badge)
![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=for-the-badge)
[![jsDelivr](https://img.shields.io/jsdelivr/npm/hm/triggle?style=for-the-badge)](https://www.jsdelivr.com/package/npm/triggle)
[![unpkg](https://img.shields.io/badge/CDN-unpkg-blue?style=for-the-badge)](https://unpkg.com/browse/triggle/)
[![View Demo](https://img.shields.io/badge/🎬%20Live-Demo-green?style=for-the-badge)](https://yesiamrocks.github.io/Triggle/)
[![Made for {css}animation](https://img.shields.io/badge/Made%20for-{css}animation-7e2ea0?style=for-the-badge&logo=css3&logoColor=white)](https://github.com/yesiamrocks/cssanimation)

[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20My%20Work-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=white)](https://www.buymeacoffee.com/yesiamrocks) [![Join Membership](https://img.shields.io/badge/Become%20a%20Member-Monthly%20Support-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=white)](https://www.buymeacoffee.com/yesiamrocks/membership)

**Triggle** is a JavaScript library that makes it easy to control CSS animations using simple HTML attributes, no dependencies required. **Triggle** lets you add animations that respond to user actions like mouse clicks, hovers, key presses, scroll events, and more. Just use intuitive `data-triggle` attributes to trigger animations exactly when and how you want them.

Whether you're building interactive buttons, scroll effects, or playful UI animations, **Triggle** works beautifully and supports options like delays, durations, and auto-reset, giving you full control with minimal code.

## Features

- Animate on `click`, `mouseenter`, `scroll`, `keydown`, etc.
- Animate any element or target another with a selector
- Reset animation classes automatically
- Toggle class on/off with a single trigger
- Trigger with keyboard key filters (`ctrl+s`, `shift+a`, `a*`)
- Chain animations using `data-triggle-next`
- Delay the next animation with `data-triggle-chain-delay`
- Trigger multiple elements at once with `data-triggle-group`
- Stagger animations across groups with `data-triggle-stagger`
- One-time animation triggers with `data-triggle-once`
- Cleanup & reinitialization support
- Developer debug logging

👉 [Live Demo](https://yesiamrocks.github.io/triggle/) | [Download via NPM](https://www.npmjs.com/package/triggle) | [Check on jsDelivr](https://www.jsdelivr.com/package/npm/triggle) | [View on unpkg](https://app.unpkg.com/triggle@1.2.0)

## Installation

### Using NPM

```bash
npm install triggle
```

Then import it in your JavaScript:

```js
// Default (unminified)
import "triggle";

// Optional: Use minified build explicitly
import "triggle/triggle.min.js";
```

### Using CDN

```html
<!-- Default build -->
<script src="https://cdn.jsdelivr.net/npm/triggle/dist/triggle.js"></script>

<!-- Minified build -->
<script src="https://cdn.jsdelivr.net/npm/triggle/dist/triggle.min.js"></script>
```

Both builds include all functionality. The minified version is optimized for production, while the unminified version is easier to debug.

## Animation Classes Powered by {css}animation

**Triggle** is designed to work hand-in-hand with the animation classes from **[{css}animation](https://github.com/yesiamrocks/cssanimation)**. These CSS classes are required to make the triggers actually animate elements, so be sure to include them in your project.

Install the animation library:

```bash
npm install @hellouxpavel/cssanimation
```

Then import it in your JavaScript:

```js
import "@hellouxpavel/cssanimation";
```

Or include it via CDN:

```html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@hellouxpavel/cssanimation@latest/dist/cssanimation.min.css" />
```

Without the cssanimation classes, **Triggle** can still detect triggers, but no animation will play.

## Getting Started

Trigger an animation on click.
To use **Triggle**, simply add `data-triggle-*` attributes to any HTML element you want to animate:

```html
<div
  class="cssanimation"
  data-triggle="click"
  data-triggle-class="ca__fx-elasticStretch"
  data-triggle-reset="true">
  Click to Animate
</div>
```

What each part does:

- `class="cssanimation"` – Required. This enables animation support from the `@hellouxpavel/cssanimation` library.
- `data-triggle` – Specifies the event(s) that trigger the animation (e.g., `click`, `mouseenter`, `keydown`).
- `data-triggle-class` – The animation class (or classes) to apply when triggered.
- `data-triggle-reset="true"` – Optional. If set to `"true"`, the animation class is removed after it finishes, allowing it to trigger again.

## Integration Tips

- Core class `.cssanimation` is required (from [{css}animation](https://github.com/yesiamrocks/cssanimation)).
- Make sure the **[{css}animation](https://github.com/yesiamrocks/cssanimation)** styles are included in your project for the animation to work properly.
- Use `data-triggle-*` attributes only on the intended element — avoid duplication on deeply nested structures to prevent conflicts.

## Supported Triggers

You can animate elements using the following trigger types via `data-triggle`:

| Trigger         | Description                          |
| --------------- | ------------------------------------ |
| `click`         | On mouse click                       |
| `dblclick`      | On double click                      |
| `mouseenter`    | When the mouse enters the element    |
| `mouseleave`    | When the mouse leaves the element    |
| `mousedown`     | On mouse button press                |
| `mouseup`       | On mouse button release              |
| `focus`         | When an input or element gains focus |
| `blur`          | When focus is lost                   |
| `input`         | When input value changes             |
| `keydown`       | On key press down                    |
| `keyup`         | On key release                       |
| `touchstart`    | On mobile touch start                |
| `touchend`      | On mobile touch end                  |
| `animationend`  | After a CSS animation completes      |
| `transitionend` | After a CSS transition completes     |
| `customEvent`   | Dispatched manually via JavaScript   |

## Attributes Reference

| Attribute                  | Type         | Description                                                                                          |
| -------------------------- | ------------ | ---------------------------------------------------------------------------------------------------- |
| `data-triggle`             | `string`     | Comma-separated events (e.g. `click,mouseenter`)                                                     |
| `data-triggle-class`       | `string`     | Space-separated CSS classes to animate                                                               |
| `data-triggle-reset`       | `true/false` | Removes animation class after it finishes                                                            |
| `data-triggle-delay`       | `string`     | CSS `animation-delay` (e.g., `0.5s`)                                                                 |
| `data-triggle-duration`    | `string`     | CSS `animation-duration` (e.g., `1s`)                                                                |
| `data-triggle-toggle`      | `true/false` | Toggles class on and off (instead of just adding)                                                    |
| `data-triggle-once`        | `true/false` | Triggers animation only once                                                                         |
| `data-triggle-target`      | `string`     | CSS selector(s) for external element(s) to animate instead of the trigger itself (e.g. `.box1, #id`) |
| `data-triggle-key`         | `string`     | Keyboard filter (e.g. `enter`, `ctrl+s`, `a*`)                                                       |
| `data-triggle-next`        | `string`     | CSS selector of element to animate **after this one finishes**                                       |
| `data-triggle-chain-delay` | `number`     | Delay (in ms) before triggering `data-triggle-next`                                                  |
| `data-triggle-group`       | `string`     | Group name to animate multiple elements together                                                     |
| `data-triggle-stagger`     | `number`     | Delay (in ms) between each group's element animation                                                 |
| `data-triggle-scroll`      | `true/false` | Use IntersectionObserver to animate when element scrolls into view                                   |
| `data-triggle-chain-loop`  | `true`       | Enables infinite looping between chained elements                                                    |

## Hover with Delay and Duration

This example shows how to trigger an animation on hover with custom timing and automatic reset:

```html
<div
  class="cssanimation"
  data-triggle="mouseenter"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-delay="0.5s"
  data-triggle-duration="2s"
  data-triggle-reset="true">
  Hover me to fade in
</div>
```

Timing Controls
Use these attributes to control animation timing:

- `data-triggle-delay="0.2s"` – Adds a delay before the animation starts.
- `data-triggle-duration="1.5s"` – Sets how long the animation should run.

## Animates Once

This example shows how to trigger an animation only for a **single time**:

```html
<div
  class="cssanimation"
  data-triggle="click"
  data-triggle-class="ca__fx-bounceIn"
  data-triggle-once="true"
  data-triggle-reset="true">
  Click Me (Animates Once)
</div>
```

- Use `data-triggle-once="true"` to ensure an animation only runs a **single time**, even if the triggering event happens again.

## Multiple Triggers

Trigger animations using more than one event by separating them with commas in the `data-triggle` attribute

```html
<div
  class="cssanimation"
  data-triggle="click, mouseenter"
  data-triggle-class="ca__fx-rubber"
  data-triggle-reset="true">
  Click and Hover me for rubber animation
</div>
```

In the example above, the animation will trigger on both `click` and `mouseenter`.

- `data-triggle="click, mouseenter""` – List multiple event types separated by commas to trigger the animation from any of them.

## Targeting Another Element

You can trigger animations on a different element using the `data-triggle-target` attribute:

```html
<button data-triggle="click" data-triggle-target="#targetBox">
  Animate Box
</button>

<div
  id="targetBox"
  class="cssanimation"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-reset="true"></div>
```

How it works

- `data-triggle-target="#box"` – Selects the element to animate.
- `data-triggle-class="ca__fx-fadeIn"` – The class that will be applied to the target when the trigger fires.

> This is useful for triggering animations from buttons, controls, or any external source.

## Targeting Multiple Element

If you want to target multiple elements, separate them with commas in the `data-triggle-target=".box, #banner, #triggleTarget"` attribute:

```html
<button
  data-triggle="click"
  data-triggle-target=".box, #banner, #triggleTarget">
  Animate All
</button>

<div
  class="cssanimation box"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-reset="true">
  Target 1 by class
</div>

<div
  id="banner"
  class="cssanimation"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-reset="true">
  Target 2 by ID
</div>

<div
  id="triggleTarget"
  class="cssanimation"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-reset="true">
  Target 3 by ID
</div>
```

How it works

- `data-triggle-target=".box, #banner, #triggleTarget"` – Selects multiple elements to animate.
- `data-triggle-class="ca__fx-fadeIn"` – The class that will be applied to the target when the trigger fires.

## Triggle Group Triggering

Trigger animations on multiple elements at once using `data-triggle-group`.

```html
<div
  class="cssanimation"
  data-triggle="click"
  data-triggle-class="ca__fx-layerPeelIn"
  data-triggle-group="cards"></div>

<div
  class="cssanimation"
  data-triggle-class="ca__fx-rollFromLeft"
  data-triggle-reset="true"
  data-triggle-group="cards"></div>

<div
  class="cssanimation"
  data-triggle-class="ca__fx-rollFromRight"
  data-triggle-reset="true"
  data-triggle-group="cards"></div>
```

How it works

- The first element acts as the **trigger**.
- All elements sharing the same `data-triggle-group="cards"` will animate together.
- Each target can use its own animation class and settings.

> Great for triggering multiple cards, icons, or UI components in sync from a single interaction.

## Triggle Toggle Animation

Use `data-triggle-toggle="true"` to turn the animation class on and off with each trigger:

```html
<div
  data-triggle="click"
  data-triggle-class="ca__fx-moonFade"
  data-triggle-toggle="true">
  Click to toggle bounce
</div>
```

How it works

- On first click, the `ca__fx-moonFade` class is added.
- On second click, the same class is removed.

This cycle continues on every interaction.

> Useful for toggling active/inactive states with a single element.

## Triggle Scroll Animation

Animate elements as they scroll into view using `data-triggle-scroll="true"`:

```html
<div
  data-triggle="scroll"
  data-triggle-scroll="true"
  data-triggle-class="ca__fx-moonFadeUp"
  data-triggle-reset="true"
  data-triggle-once="true">
  I animate when visible
</div>
```

How it works

- Triggers the `ca__fx-moonFadeUp` animation once when at least 50% of the element enters the viewport.
- `data-triggle-once="true"` ensures the animation happens only once per page load.
- `data-triggle-reset="true"` allows it to reset after animation completes (if `once` is not used).

> Perfect for scroll-based reveals and in-view transitions.

## Triggle Scroll-Based Staggered Animation

Use `data-triggle-group` and `data-triggle-stagger` to animate multiple elements in a coordinated sequence when a trigger element comes into view.

Trigger Element:

```html
<div
  data-triggle="scroll"
  data-triggle-scroll="true"
  data-triggle-group="TrgScroll"
  data-triggle-class="ca__fx-moonFadeScaleUp"
  data-triggle-stagger="300"
  data-triggle-once="true"></div>
```

Staggered/Grouped Targets:

```html
<div
  data-triggle-class="ca__fx-moonFadeLeft"
  data-triggle-reset="true"
  data-triggle-group="TrgScroll">
  Card A
</div>

<div
  data-triggle-class="ca__fx-moonFadeRight"
  data-triggle-reset="true"
  data-triggle-group="TrgScroll">
  Card B
</div>

<div
  data-triggle-class="ca__fx-moonFade"
  data-triggle-reset="true"
  data-triggle-group="TrgScroll">
  Card C
</div>
```

How it works

- The **trigger element** activates the animation for all elements in the matching `data-triggle-group`.
- The `data-triggle-stagger="300"` adds a 300ms delay between each target's animation.
- Use `data-triggle-once="true"` if you want the animation only fires once when the group scrolls into view.
- Use `data-triggle-reset="true"` if you want the animation to fire every time the group scrolls into view.

> Great for scroll reveals, feature sections, or card-based layouts with subtle animation cascades.

## Triggle Chained Animation

Chain multiple animations by using `data-triggle-next` and control timing with `data-triggle-chain-delay`.

```html
<button
  data-triggle="click"
  data-triggle-class="ca__fx-swingIn"
  data-triggle-reset="true"
  data-triggle-next="#step2"
  data-triggle-chain-delay="500">
  Start
</button>

<div
  id="step2"
  data-triggle-class="ca__fx-systemBootIn"
  data-triggle-reset="true" />
```

When the button is clicked:

- It animates with `ca__fx-swingIn`
- After `ca__fx-swingIn` finishes, triggle waits 500ms and then triggers `#step2`
- `#step2` animates using the `ca__fx-systemBootIn` class

Key Attributes

- `data-triggle-next="#selector"` – Defines the next element to animate in sequence.
- `data-triggle-chain-delay="500"` – Wait time in milliseconds before triggering the next animation.

> Use chaining for guided flows, multi-step reveals, or onboarding sequences.

## Chain Loop Example (data-triggle-chain-loop)

Create an infinite loop of chained animations between two or more elements.

```html
<div
  id="box1"
  data-triggle="click"
  data-triggle-class="ca__fx-squishPop"
  data-triggle-next="#box2"
  data-triggle-chain-delay="500"
  data-triggle-chain-loop="true">
  Start Loop
</div>

<div
  id="box2"
  data-triggle-class="ca__fx-layerPeelOut"
  data-triggle-next="#box1"
  data-triggle-chain-delay="500"></div>
```

How it works

- Clicking on `#box1` starts the loop.
- `#box1` animates with `ca__fx-squishPop`, then triggers `#box2` after `500ms`.
- `#box2` animates with `ca__fx-layerPeelOut`, then triggers `#box1` after `500ms`.
- Because `data-triggle-chain-loop="true"` is set, the chain will repeat indefinitely.

> Useful for animated banners, instructional sequences, or continuous UI feedback loops.

## Keyboard Filter Example

Limit animations to specific key presses using `data-triggle-key`.

```html
<div
  data-triggle="keydown"
  data-triggle-class="ca__fx-fadeIn"
  data-triggle-key="ctrl+k,shift+a,a*"
  data-triggle-reset="true">
  Press keys
</div>
```

Supports:

- Single key match (a) `data-triggle-key="Enter,Escape"`
- Wildcards (a\* matches abc) `data-triggle-key="en*, arrow*"`
- Modifier keys (ctrl+s, shift+enter, alt+x) `data-triggle-key="ctrl+z, shift+a, alt+x"`

## Custom Events

You can use any event name for `data-triggle`. This allows you to create custom event triggers using JavaScript's `dispatchEvent()` method. Example: `data-triggle="notify"` can be triggered by: `element.dispatchEvent(new Event("notify"));`

```html
<div
  id="notify"
  data-triggle="customTriggleEvent"
  data-triggle-class="ca__fx-flipX"
  data-triggle-reset="true"></div>

<script>
  document
    .getElementById("notify")
    .dispatchEvent(new Event("customTriggleEvent"));
</script>
```

## Manual Animation Trigger (Optional)

If you prefer programmatic control, you can manually trigger animations using `window.triggle.apply()`.

```js
window.triggle.apply(
  document.querySelector("#element"),
  "ca__fx-jelly", // Animation class to apply
  true, // Reset after animation ends
  "0.3s", // Delay before animation starts
  "1s", // Duration of the animation
  false // Toggle mode (true = toggle, false = one-time)
);
```

Parameters

- **Element** – The target DOM element
- **Class Name** – Animation class to apply
- **Reset** – Whether to remove the class after animation ends
- **Delay** – Optional delay before the animation starts (e.g., `"0.3s"`)
- **Duration** – Optional animation duration (e.g., `"1s"`)
- **Toggle** – Set to `true` to toggle the class on/off

> Ideal for triggering animations based on app logic, user input, or custom events.

## Cleanup

If you're using **Triggle** in a single-page app (SPA) or need to reinitialize after DOM changes:

```js
window.triggle.destroy(); // Removes all event listeners
window.triggle.init(); // Re-initializes all triggers
```

## Global Disable (Optional)

You can globally disable all **Triggle** animations, useful for accessibility, performance testing, or reduced motion preferences:

```js
window.__trg_TRIGGER_DISABLED = true;
```

To re-enable:

```js
window.__trg_TRIGGER_DISABLED = false;
window.triggle.init();
```

## Debug Mode

Enable debug mode to log internal behavior and aid in troubleshooting:

```js
window.__trg_DEBUG = true;
```

## Supported Passive Events

To improve performance, **Triggle** uses passive event listeners for the following triggers:

- `touchstart`
- `touchend`
- `scroll`

## Library Architecture Summary

- **Lightweight** and dependency-free — built with vanilla JavaScript
- Initializes quickly using `DOMContentLoaded` for efficient event binding
- Leverages native CSS for animation timing (`delay`, `duration`)
- Easy to integrate — just add `data-triggle-*` attributes and go
- Automatically cleans up using the `animationend` event
- Built with extensibility in mind — easy to add new trigger types or behaviors

## License

**Triggle** is proudly open-sourced under the [Apache License 2.0](./LICENSE). You can freely use it in personal, commercial, and creative projects.

Want a quick explanation? See the [License Summary →](./ABOUT-LICENSE.md)

## Contribute

We welcome all contributions — whether it’s fixing bugs, adding feature, improving docs, or sharing ideas!

- Found an issue? [Open a GitHub Issue](https://github.com/yesiamrocks/triggle/issues)
- Want to improve the library? [Submit a Pull Request](https://github.com/yesiamrocks/triggle/pulls)
- Have questions or feature ideas? [Start a Discussion](https://github.com/yesiamrocks/triggle/discussions)

Help us make **Triggle** even more magical for everyone.

## Need Help?

Running into issues while using **Triggle** in your project?  
Whether it's a website, landing page, tool, or framework integration, we're here to help!

- Report bugs or problems via [GitHub Issues](https://github.com/yesiamrocks/triggle/issues)
- Ask questions or get guidance in [GitHub Discussions](https://github.com/yesiamrocks/triggle/discussions)

We’re happy to assist and make sure everything works smoothly in your setup.

## Support This Project

If **Triggle** has saved you time, added a little magic to your UI, or helped bring your creative vision to life — please consider supporting its development.

This project is built with care, during late nights and weekends, with a passion for open-source and motion design. Your support helps me:

- Keep the library up to date and bug-free
- Add new features and animation triggers

Every coffee counts — thank you for helping me keep creating. 🙏

[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20My%20Work-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=white)](https://www.buymeacoffee.com/yesiamrocks)

## Become a Community Sponsor

If **Triggle** helped you ship faster, spark delight in your UI, or just made your day as a developer easier — I’d be honored to have your support.

This isn’t a big team or a funded project. It’s just me — **Pavel** — building tools I wish existed.  
From late nights to early mornings, I pour love into every animation, every feature, every detail — to make the creative process more fun, expressive, and empowering for makers like you.

Your sponsorship helps me:

- Keep the library free and open for everyone
- Push out new triggers, animation packs, and ideas faster
- Write thoughtful dev/design content via my newsletter  
  👉 [Pixels & Projects with Pavel](https://www.linkedin.com/newsletters/pixels-projects-with-pavel-7093275757006782464/)

### As a Community Sponsor, you'll receive:

- A shoutout in the newsletter
- Your name or project proudly featured in the documentation and site
- My sincere gratitude for backing indie creativity on the web

Let’s build a more playful, animated web — together.

[![Join Membership](https://img.shields.io/badge/Become%20a%20Member-Monthly%20Support-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=white)](https://www.buymeacoffee.com/yesiamrocks/membership)

<br>

---

![Built with ❤️ by Pavel](https://img.shields.io/badge/Built%20with-%E2%9D%A4%EF%B8%8F%20by%20Pavel-orange?style=for-the-badge) [![LinkedIn](https://img.shields.io/badge/LinkedIn-@shafayetul-blue?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/shafayetul/) [![Twitter](https://img.shields.io/badge/Twitter-@yesiamrocks-1DA1F2?style=for-the-badge&logo=x&logoColor=white)](https://twitter.com/yesiamrocks) [![Email](https://img.shields.io/badge/Email-yesiamrocks@gmail.com-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:yesiamrocks@gmail.com) [![Newsletter](https://img.shields.io/badge/Pixels_&_Projects_with_Pavel-Subscribe-a6ca4b?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/newsletters/pixels-projects-with-pavel-7093275757006782464/)
