Class presets
init({ presets }) lets you set animations once globally. Every element matching a given class behaves as if it had the listed aa-* attributes — without touching the DOM.
This is the Webflow shortcut: instead of opening every .heading-style-h2 symbol and adding aa-animate="text-fade-up", you set it once at init and the library applies it to every match on the page.
AlrdyAnimate.init({ presets: { // String shorthand — sets aa-animate only 'heading-style-h2': 'text-fade-up',
// Object — each bare key prefixed with aa- becomes a virtual attribute 'heading-style-h3': { animate: 'text-blur-up', split: 'words', duration: '0.8|0.5', // pipe variants work just like in HTML stagger: '0.05', },
'cta-button': { animate: 'fade-up', duration: '0.4|0.3' }, },})| Value form | Maps to |
|---|---|
string | { animate: <string> } — sets aa-animate only |
| object | each bare key prefixed with aa- (e.g. split → aa-split, duration-md → aa-duration-md) |
Pipe variants ('0.8|0.5') and Tailwind-style breakpoint suffix keys ('animate-md') work because preset values flow through the same readAttrs() parser as real HTML attributes.
| Rule | Behaviour |
|---|---|
| Per-element override | If an element already has any aa-* attribute, the preset is skipped for that element. The explicit attribute always wins. |
Required animate | Each preset must include animate (or a per-breakpoint variant). Presets without one are dropped — with debug: true, you get a console warning. |
| Resolution order | Object insertion order. The first preset entry that matches an element wins; later entries don't merge. |
Reduced motion / optimizeMobile | Preset elements collapse to the same opacity-fade fallback as hand-authored attributes — no extra wiring. |
| No DOM mutation | Presets resolve into an in-memory Map<Element, Config>. The browser inspector shows the element untouched. |
| No FOUC guard | The visibility: hidden until aa-ready rule only catches elements that have aa-animate in the initial HTML. Use presets for below-the-fold content; hand-author aa-animate on anything above the fold. |
Live demo
Section titled “Live demo”PresetsDemo initialises with this preset map:
AlrdyAnimate.init({ presets: { 'heading-style-h2': { animate: 'text-fade-up', split: 'lines' }, 'heading-style-h3': { animate: 'text-blur-up', split: 'words' }, 'cta-card': { animate: 'fade-up', duration: '0.4|0.3' }, },})None of the elements below have aa-* attributes — they animate purely from the class match. Scroll down to bring them into view. (Open DevTools to confirm: no aa-animate on the markup.)
Heading h2 — text-fade-up, split lines
Heading h3 — text-blur-up, split words
Override demo
Section titled “Override demo”This h2 carries the same heading-style-h2 class but adds an explicit aa-animate="fade-right". The preset is skipped — the explicit attribute wins.
override: fade-right via explicit attribute
When to use presets vs hand-authored attributes
Section titled “When to use presets vs hand-authored attributes”Reach for a preset when…
- the animation should be consistent for every instance of a class (
heading-style-h2,cta-button,card-h3), - you have many elements of the same kind and don't want to touch each one in Webflow,
- the element is below the fold (presets don't trigger the visibility-hidden FOUC rule).
Hand-author aa-* directly when…
- the element is one-of-a-kind (a hero headline, a single feature callout),
- the element is above the fold and must be hidden by the FOUC guard until init flips
aa-ready, - you need per-element variation that doesn't fit cleanly into a class.
Reduced motion + optimizeMobile
Section titled “Reduced motion + optimizeMobile”Preset elements are indistinguishable from hand-authored ones during the reduced-motion / optimizeMobile fallback passes:
- Under
reducedMotion,text-*and appear (fade-*,zoom-*,slide-*,blur-in,rotate-*) presets collapse to a simple opacity fade;parallaxpresets are skipped. - Under
optimizeMobile, onlytext-*andparallaxpresets are affected (appear presets run normally).parallaxis skipped;text-*is simply made visible (optimizeMobile: true) or soft-faded (optimizeMobile: 'fade'). - Any preset element targeted by a fade pass uses the same timing as hand-authored elements.
No extra wiring required — the preset map is consulted by the fallback pass alongside real attribute lookups.
Presets are intended for text (text-*) and appear (fade-*, zoom-*, slide-*, blur-in, rotate-*) animations. You can technically include other aa-* keys in a preset object (trigger, scrub, stagger, etc.), but feature-anchor attributes like aa-tabs, aa-slider, aa-marquee, aa-nav, aa-modal-*, aa-cursor, aa-hover are out of the documented use case — those are single-element opt-ins or interactive components, not class-driven animations.