Animate On Scroll
A fully customizable and versatile component for adding scroll-triggered animations to different elements on your page.
Introduction
The ZyfloAOS component is a powerful and flexible tool for adding scroll-triggered animations to elements on your page. It uses Framer Motion to create smooth, customizable animations that activate as the element comes into view.
Add The Component
Add the following component to your project in the /components/zyflo
directory:
"use client"
import React, { ReactNode } from "react"
import { motion, Variants, HTMLMotionProps } from "framer-motion"
export const PossibleZyfloAOSVariants = [
"fade",
"slide-left",
"slide-right",
"slide-top",
"slide-bottom",
"slide-top-right",
"slide-top-left",
"slide-bottom-right",
"slide-bottom-left",
"scale-center",
"scale-left",
"scale-right",
"scale-bottom",
"scale-top",
"scale-top-right",
"scale-top-left",
"scale-bottom-right",
"scale-bottom-left",
"rotate-left",
"rotate-right",
"rotate-bottom",
"rotate-top",
"rotate-top-right",
"rotate-top-left",
"rotate-bottom-right",
"rotate-bottom-left",
"flip-left",
"flip-right",
"flip-bottom",
"flip-top",
"flip-top-right",
"flip-top-left",
"flip-bottom-right",
"flip-bottom-left"
] as const
export type ZyfloAOSVariant = (typeof PossibleZyfloAOSVariants)[number]
export const PossibleZyfloAOSEasings = [
"ease-in",
"ease-out",
"ease-in-out",
"circ-out",
"spring"
] as const
export type ZyfloAOSEasing = (typeof PossibleZyfloAOSEasings)[number]
const createVariants = (
variant: ZyfloAOSVariant,
duration: number,
easing: ZyfloAOSEasing
): Variants => {
const baseVariants: Variants = {
hidden: {
opacity: 0
},
visible: {
opacity: 1,
transition:
easing === "spring"
? { type: "spring", bounce: 0.5, duration }
: { duration, ease: getEasing(easing) }
}
}
const transitionProps =
easing === "spring"
? {
type: "spring",
bounce: 0.5,
duration
}
: {
duration,
ease: getEasing(easing),
opacity: { duration: duration * 0.75 }
}
switch (variant) {
case "slide-left":
return {
...baseVariants,
hidden: { x: "-50%", opacity: 0 },
visible: { x: 0, opacity: 1, transition: transitionProps }
}
case "slide-right":
return {
...baseVariants,
hidden: { x: "50%", opacity: 0 },
visible: { x: 0, opacity: 1, transition: transitionProps }
}
case "slide-top":
return {
...baseVariants,
hidden: { y: "-50%", opacity: 0 },
visible: { y: 0, opacity: 1, transition: transitionProps }
}
case "slide-bottom":
return {
...baseVariants,
hidden: { y: "50%", opacity: 0 },
visible: { y: 0, opacity: 1, transition: transitionProps }
}
case "slide-top-right":
return {
...baseVariants,
hidden: { x: "50%", y: "-50%", opacity: 0 },
visible: { x: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "slide-top-left":
return {
...baseVariants,
hidden: { x: "-50%", y: "-50%", opacity: 0 },
visible: { x: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "slide-bottom-right":
return {
...baseVariants,
hidden: { x: "50%", y: "50%", opacity: 0 },
visible: { x: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "slide-bottom-left":
return {
...baseVariants,
hidden: { x: "-50%", y: "50%", opacity: 0 },
visible: { x: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "scale-center":
return {
...baseVariants,
hidden: { scale: 0, opacity: 0 },
visible: { scale: 1, opacity: 1, transition: transitionProps }
}
case "scale-left":
return {
...baseVariants,
hidden: { scale: 0, x: "-50%", opacity: 0 },
visible: { scale: 1, x: 0, opacity: 1, transition: transitionProps }
}
case "scale-right":
return {
...baseVariants,
hidden: { scale: 0, x: "50%", opacity: 0 },
visible: { scale: 1, x: 0, opacity: 1, transition: transitionProps }
}
case "scale-bottom":
return {
...baseVariants,
hidden: { scale: 0, y: "50%", opacity: 0 },
visible: { scale: 1, y: 0, opacity: 1, transition: transitionProps }
}
case "scale-top":
return {
...baseVariants,
hidden: { scale: 0, y: "-100%", opacity: 0 },
visible: { scale: 1, y: 0, opacity: 1, transition: transitionProps }
}
case "scale-top-right":
return {
...baseVariants,
hidden: {
x: "50%",
y: "-50%",
scale: 0,
opacity: 0
},
visible: {
x: 0,
y: 0,
scale: 1,
opacity: 1,
transition: transitionProps
}
}
case "scale-top-left":
return {
...baseVariants,
hidden: {
x: "-50%",
y: "-50%",
scale: 0,
opacity: 0
},
visible: {
x: 0,
y: 0,
scale: 1,
opacity: 1,
transition: transitionProps
}
}
case "scale-bottom-right":
return {
...baseVariants,
hidden: { scale: 0, x: "50%", y: "50%", opacity: 0 },
visible: {
scale: 1,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "scale-bottom-left":
return {
...baseVariants,
hidden: { scale: 0, x: "-50%", y: "50%", opacity: 0 },
visible: {
scale: 1,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "fade":
return {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition:
easing === "spring"
? { type: "spring", bounce: 0.5, duration }
: { duration, ease: getEasing(easing) }
}
}
case "rotate-left":
return {
...baseVariants,
hidden: { rotate: -45, x: "-25%", opacity: 0 },
visible: { rotate: 0, x: 0, opacity: 1, transition: transitionProps }
}
case "rotate-right":
return {
...baseVariants,
hidden: { rotate: 45, x: "25%", opacity: 0 },
visible: { rotate: 0, x: 0, opacity: 1, transition: transitionProps }
}
case "rotate-bottom":
return {
...baseVariants,
hidden: { rotate: 45, y: "25%", opacity: 0 },
visible: { rotate: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "rotate-top":
return {
...baseVariants,
hidden: { rotate: -45, y: "-25%", opacity: 0 },
visible: { rotate: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "rotate-top-right":
return {
...baseVariants,
hidden: { rotate: 45, x: "25%", y: "-25%", opacity: 0 },
visible: {
rotate: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "rotate-top-left":
return {
...baseVariants,
hidden: { rotate: -45, x: "-25%", y: "-25%", opacity: 0 },
visible: {
rotate: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "rotate-bottom-right":
return {
...baseVariants,
hidden: { rotate: 45, x: "25%", y: "25%", opacity: 0 },
visible: {
rotate: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "rotate-bottom-left":
return {
...baseVariants,
hidden: { rotate: -45, x: "-25%", y: "25%", opacity: 0 },
visible: {
rotate: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "flip-left":
return {
...baseVariants,
hidden: { rotateY: 180, x: "-25%", opacity: 0 },
visible: { rotateY: 0, x: 0, opacity: 1, transition: transitionProps }
}
case "flip-right":
return {
...baseVariants,
hidden: { rotateY: -180, x: "25%", opacity: 0 },
visible: { rotateY: 0, x: 0, opacity: 1, transition: transitionProps }
}
case "flip-bottom":
return {
...baseVariants,
hidden: { rotateX: -180, y: "25%", opacity: 0 },
visible: { rotateX: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "flip-top":
return {
...baseVariants,
hidden: { rotateX: 180, y: "-25%", opacity: 0 },
visible: { rotateX: 0, y: 0, opacity: 1, transition: transitionProps }
}
case "flip-top-right":
return {
...baseVariants,
hidden: {
rotateX: 90,
rotateY: -90,
x: "25%",
y: "-25%",
opacity: 0
},
visible: {
rotateX: 0,
rotateY: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "flip-top-left":
return {
...baseVariants,
hidden: {
rotateX: 90,
rotateY: 90,
x: "-25%",
y: "-25%",
opacity: 0
},
visible: {
rotateX: 0,
rotateY: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "flip-bottom-right":
return {
...baseVariants,
hidden: {
rotateX: -90,
rotateY: -90,
x: "25%",
y: "25%",
opacity: 0
},
visible: {
rotateX: 0,
rotateY: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
case "flip-bottom-left":
return {
...baseVariants,
hidden: {
rotateX: -90,
rotateY: 90,
x: "-25%",
y: "25%",
opacity: 0
},
visible: {
rotateX: 0,
rotateY: 0,
x: 0,
y: 0,
opacity: 1,
transition: transitionProps
}
}
default:
return baseVariants
}
}
export interface ZyfloAOSProps extends HTMLMotionProps<"div"> {
children: ReactNode
amount?: number
once?: boolean
variant?: ZyfloAOSVariant
duration?: number
easing?: ZyfloAOSEasing
}
const getEasing = (easing: ZyfloAOSEasing) => {
switch (easing) {
case "ease-in":
return "easeIn"
case "ease-out":
return "easeOut"
case "ease-in-out":
return "easeInOut"
case "spring":
return "spring"
case "circ-out":
return "circOut"
default:
return easing
}
}
const ZyfloAOS: React.FC<ZyfloAOSProps> = ({
children,
amount = 0,
once = false,
className,
variant = "fade",
duration = 0.5,
easing = "ease-in-out",
...props
}) => {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ amount, once }}
variants={createVariants(variant, duration, easing)}
transition={
easing === "spring"
? { type: "spring", bounce: 0.5, duration }
: { duration, ease: getEasing(easing) }
}
{...props}
>
{children}
</motion.div>
)
}
export default ZyfloAOS
Usage
Here's a basic example of how to use the AOS component:
import ZyfloAOS from "@/components/zyflo/aos"
export default function MyPage() {
return (
<ZyfloAOS
once={false}
amount={0.4}
duration={1.2}
easing="spring"
variant="slide-left"
>
<div className="flex size-52 items-center justify-center">
<p>Content goes here</p>
</div>
</ZyfloAOS>
)
}
Examples
Here are all of the examples of how to use the ZyfloAOS component with all the different variants available:
Fade Variant
Content goes here
Slide Left Variant
Content goes here
Slide Right Variant
Content goes here
Slide Top Variant
Content goes here
Slide Bottom Variant
Content goes here
Slide Top Right Variant
Content goes here
Slide Top Left Variant
Content goes here
Slide Bottom Right Variant
Content goes here
Slide Bottom Left Variant
Content goes here
Scale Center Variant
Content goes here
Scale Left Variant
Content goes here
Scale Right Variant
Content goes here
Scale Bottom Variant
Content goes here
Scale Top Variant
Content goes here
Scale Top Right Variant
Content goes here
Scale Top Left Variant
Content goes here
Scale Bottom Right Variant
Content goes here
Scale Bottom Left Variant
Content goes here
Rotate Left Variant
Content goes here
Rotate Right Variant
Content goes here
Rotate Bottom Variant
Content goes here
Rotate Top Variant
Content goes here
Rotate Top Right Variant
Content goes here
Rotate Top Left Variant
Content goes here
Rotate Bottom Right Variant
Content goes here
Rotate Bottom Left Variant
Content goes here
Flip Left Variant
Content goes here
Flip Right Variant
Content goes here
Flip Bottom Variant
Content goes here
Flip Top Variant
Content goes here
Flip Top Right Variant
Content goes here
Flip Top Left Variant
Content goes here
Flip Bottom Right Variant
Content goes here
Flip Bottom Left Variant
Content goes here
Props
Quick Props View
The ZyfloAOS component accepts the following props:
Prop | Description |
---|---|
children | The content to be animated |
variant | The animation variant to use |
duration | The duration of the animation in seconds |
easing | The easing function to use for the animation |
amount | The amount of the element that needs to be visible to trigger the animation |
once | Whether the animation should only trigger once |
Detailed Props View
children
The children
prop is the content to be animated. It accepts a ReactNode.
variant
The variant
prop is the animation variant to use. It accepts a string and can be any of the following:
fade
slide-left
slide-right
slide-top
slide-bottom
slide-top-right
slide-top-left
slide-bottom-right
slide-bottom-left
scale-center
scale-left
scale-right
scale-bottom
scale-top
scale-top-right
scale-top-left
scale-bottom-right
scale-bottom-left
rotate-left
rotate-right
rotate-bottom
rotate-top
rotate-top-right
rotate-top-left
rotate-bottom-right
rotate-bottom-left
flip-left
flip-right
flip-bottom
flip-top
flip-top-right
flip-top-left
flip-bottom-right
flip-bottom-left
duration
The duration
prop is the duration of the animation in seconds. It accepts a number.
easing
The easing
prop is the easing function to use for the animation. It accepts a string and can be any of the following:
ease-in
ease-out
ease-in-out
circ-out
spring
amount
The amount
prop is the amount of the element that needs to be visible to trigger the animation. It accepts a number.
once
The once
prop is whether the animation should only trigger once. It accepts a boolean.
className
The className
prop is the class name to be applied to the animated element. It accepts a string.
Customization
The component uses Framer Motion for animations. You can customize its behavior by modifying the props or extending the component in your project.
Accessibility
When using animations, consider the following accessibility guidelines:
- Use animations sparingly to avoid overwhelming users or causing motion sickness.
- Provide a way for users to disable animations if needed.
- Ensure that important content is still accessible even if animations are disabled.
Notes
- The component uses Framer Motion for animations. Make sure you have Framer Motion installed in your project.
- Performance may be affected if you use too many animated elements on a single page.
Contributing
If you find any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request on our GitHub repository. We appreciate your contributions and are always open to collaboration.
Thank you for considering contributing to Zyflo!