Slide

PreviousNext

An effect that allows you to animate elements with a slide effect on first view or load.

Docs
animate-uiui

Preview

Loading preview…
registry/primitives/effects/slide/index.tsx
'use client';

import * as React from 'react';
import { motion, type HTMLMotionProps, type Variant } from 'motion/react';

import {
  useIsInView,
  type UseIsInViewOptions,
} from '@/hooks/use-is-in-view';
import { Slot, type WithAsChild } from '@/components/animate-ui/primitives/animate/slot';

type SlideDirection = 'up' | 'down' | 'left' | 'right';

type SlideProps = WithAsChild<
  {
    children?: React.ReactNode;
    delay?: number;
    direction?: SlideDirection;
    offset?: number;
    ref?: React.Ref<HTMLElement>;
  } & UseIsInViewOptions &
    HTMLMotionProps<'div'>
>;

function Slide({
  ref,
  transition = { type: 'spring', stiffness: 200, damping: 20 },
  delay = 0,
  inView = false,
  inViewMargin = '0px',
  inViewOnce = true,
  direction = 'up',
  offset = 100,
  asChild = false,
  ...props
}: SlideProps) {
  const { ref: localRef, isInView } = useIsInView(
    ref as React.Ref<HTMLElement>,
    {
      inView,
      inViewOnce,
      inViewMargin,
    },
  );

  const axis = direction === 'up' || direction === 'down' ? 'y' : 'x';
  const hidden: Variant = {
    [axis]: direction === 'right' || direction === 'down' ? -offset : offset,
  };
  const visible: Variant = { [axis]: 0 };

  const Component = asChild ? Slot : motion.div;

  return (
    <Component
      ref={localRef as React.Ref<HTMLDivElement>}
      initial="hidden"
      animate={isInView ? 'visible' : 'hidden'}
      exit="hidden"
      variants={{ hidden, visible }}
      transition={{
        ...transition,
        delay: (transition?.delay ?? 0) + delay / 1000,
      }}
      {...props}
    />
  );
}

type SlideListProps = Omit<SlideProps, 'children'> & {
  children: React.ReactElement | React.ReactElement[];
  holdDelay?: number;
};

function Slides({
  children,
  delay = 0,
  holdDelay = 0,
  ...props
}: SlideListProps) {
  const array = React.Children.toArray(children) as React.ReactElement[];

  return (
    <>
      {array.map((child, index) => (
        <Slide
          key={child.key ?? index}
          delay={delay + index * holdDelay}
          {...props}
        >
          {child}
        </Slide>
      ))}
    </>
  );
}

export {
  Slide,
  Slides,
  type SlideProps,
  type SlideListProps,
  type SlideDirection,
};

Installation

npx shadcn@latest add @animate-ui/primitives-effects-slide

Usage

import { PrimitivesEffectsSlide } from "@/components/ui/primitives-effects-slide"
<PrimitivesEffectsSlide />