Skip to content

Instantly share code, notes, and snippets.

@Vadorequest
Created August 23, 2021 15:17
Show Gist options
  • Save Vadorequest/3ee2c6a21c3cba9cf9adbe20232b68bf to your computer and use it in GitHub Desktop.
Save Vadorequest/3ee2c6a21c3cba9cf9adbe20232b68bf to your computer and use it in GitHub Desktop.
Framer Motion "ShowInView" component - Displays children when visible in the viewport
import {
domAnimation,
LazyMotion,
m as motion,
useAnimation,
} from 'framer-motion';
import { CustomDomComponent } from 'framer-motion/types/render/dom/motion-proxy';
import {
Transition,
Variant,
} from 'framer-motion/types/types';
import React, { useEffect } from 'react';
import {
IntersectionOptions,
useInView,
} from 'react-intersection-observer';
type Props = {
children: React.ReactNode;
intersectionOptions?: IntersectionOptions;
transition?: Transition;
visible?: Variant;
hidden?: Variant;
onInView?: () => null;
MotionComponent?: CustomDomComponent<any>;
};
/**
* Displays the children (within a Motion component wrapper) when the wrapper is visible in the viewport.
*
* Works by creating a transition from "hidden" to "visible", which changes the "opacity" property.
*
* @example
import { m as motion } from 'framer-motion';
<ShowInView MotionComponent={motion.div}>
Hello world
</ShowInView>
*/
const ShowInView: React.FunctionComponent<Props> = (props): JSX.Element => {
const {
children,
intersectionOptions = { delay: 200 },
transition = { duration: 0.3 },
visible = {},
hidden = {},
onInView,
MotionComponent = motion.div,
} = props;
const controls = useAnimation();
const [ref, inView] = useInView({
triggerOnce: true,
...intersectionOptions,
});
useEffect(() => {
if (inView) {
controls.start('visible');
if (typeof onInView === 'function') {
onInView?.();
}
}
}, [controls, inView, onInView]);
return (
// Optimize using async loading - See https://www.framer.com/api/motion/guide-reduce-bundle-size/#how-to-reduce-bundle-size
<LazyMotion features={domAnimation} strict>
<MotionComponent
ref={ref}
animate={controls}
initial="hidden"
transition={transition}
variants={{
visible: {
opacity: 1,
...visible,
},
hidden: {
opacity: 0,
...hidden,
},
}}
>
{children}
</MotionComponent>
</LazyMotion>
);
};
export default ShowInView;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment