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.
- 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 | Download via NPM | Check on jsDelivr | View on unpkg
npm install triggle
Then import it in your JavaScript:
// Default (unminified)
import "triggle";
// Optional: Use minified build explicitly
import "triggle/triggle.min.js";
<!-- 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.
Triggle is designed to work hand-in-hand with the animation classes from {css}animation. 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:
npm install @hellouxpavel/cssanimation
Then import it in your JavaScript:
import "@hellouxpavel/cssanimation";
Or include it via CDN:
<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.
Trigger an animation on click.
To use Triggle, simply add data-triggle-*
attributes to any HTML element you want to animate:
<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.
- Core class
.cssanimation
is required (from {css}animation). - Make sure the {css}animation 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.
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 |
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 |
This example shows how to trigger an animation on hover with custom timing and automatic reset:
<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.
This example shows how to trigger an animation only for a single time:
<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.
Trigger animations using more than one event by separating them with commas in the data-triggle
attribute
<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.
You can trigger animations on a different element using the data-triggle-target
attribute:
<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.
If you want to target multiple elements, separate them with commas in the data-triggle-target=".box, #banner, #triggleTarget"
attribute:
<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.
Trigger animations on multiple elements at once using data-triggle-group
.
<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.
Use data-triggle-toggle="true"
to turn the animation class on and off with each trigger:
<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.
Animate elements as they scroll into view using data-triggle-scroll="true"
:
<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 (ifonce
is not used).
Perfect for scroll-based reveals and in-view transitions.
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:
<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:
<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.
Chain multiple animations by using data-triggle-next
and control timing with data-triggle-chain-delay
.
<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 theca__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.
Create an infinite loop of chained animations between two or more elements.
<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 withca__fx-squishPop
, then triggers#box2
after500ms
.#box2
animates withca__fx-layerPeelOut
, then triggers#box1
after500ms
.- Because
data-triggle-chain-loop="true"
is set, the chain will repeat indefinitely.
Useful for animated banners, instructional sequences, or continuous UI feedback loops.
Limit animations to specific key presses using data-triggle-key
.
<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"
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"));
<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>
If you prefer programmatic control, you can manually trigger animations using window.triggle.apply()
.
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.
If you're using Triggle in a single-page app (SPA) or need to reinitialize after DOM changes:
window.triggle.destroy(); // Removes all event listeners
window.triggle.init(); // Re-initializes all triggers
You can globally disable all Triggle animations, useful for accessibility, performance testing, or reduced motion preferences:
window.__trg_TRIGGER_DISABLED = true;
To re-enable:
window.__trg_TRIGGER_DISABLED = false;
window.triggle.init();
Enable debug mode to log internal behavior and aid in troubleshooting:
window.__trg_DEBUG = true;
To improve performance, Triggle uses passive event listeners for the following triggers:
touchstart
touchend
scroll
- 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
Triggle is proudly open-sourced under the Apache License 2.0. You can freely use it in personal, commercial, and creative projects.
Want a quick explanation? See the License Summary →
We welcome all contributions — whether it’s fixing bugs, adding feature, improving docs, or sharing ideas!
- Found an issue? Open a GitHub Issue
- Want to improve the library? Submit a Pull Request
- Have questions or feature ideas? Start a Discussion
Help us make Triggle even more magical for everyone.
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
- Ask questions or get guidance in GitHub Discussions
We’re happy to assist and make sure everything works smoothly in your setup.
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. 🙏
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
- 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.