UI Animations
Docs
Resizable Panel

Resizable Panel

Resizable panel component

Loading...

Installation

Install the following dependencies:

npm install react-use-measure

Copy and paste the following code into your project.

'use client';
 
import { AnimatePresence, motion, Transition } from 'framer-motion';
import { ComponentProps, createContext, ReactNode, useContext } from 'react';
import useMeasure from 'react-use-measure';
 
const PanelContext = createContext({ value: '' });
 
interface ResizablePanelProps extends ComponentProps<'div'> {
  children: ReactNode;
  value?: string;
  transition?: Transition;
}
 
const ResizablePanel: React.FC<ResizablePanelProps> = ({
  children,
  value,
  transition,
  ...rest
}) => {
  const [ref, bounds] = useMeasure();
 
  return (
    <motion.div
      animate={{ height: bounds.height > 0 ? bounds.height : undefined }}
      transition={transition}
      className='relative overflow-hidden'
    >
      <div ref={ref}>
        <PanelContext.Provider value={{ value: value ? value : '' }}>
          <div {...rest}>{children}</div>
        </PanelContext.Provider>
      </div>
    </motion.div>
  );
};
 
interface ResizablePanelContentProps extends ComponentProps<'div'> {
  values?: string[];
  children: ReactNode;
}
 
const transition = {
  type: 'ease',
  ease: 'easeInOut',
  duration: 0.4,
};
 
const ResizablePanelContent: React.FC<ResizablePanelContentProps> = ({
  values,
  children,
  ...rest
}) => {
  const panelContext = useContext(PanelContext);
  const isActive = values ? values.includes(panelContext.value) : true;
 
  return (
    <AnimatePresence mode='popLayout' initial={false}>
      {isActive && (
        <motion.div
          initial={{ opacity: 0 }}
          animate={{
            opacity: 1,
            transition: {
              ...transition,
              duration: transition.duration / 2,
              delay: 0.3,
            },
          }}
          exit={{
            opacity: 0,
            transition: {
              ...transition,
              duration: transition.duration / 2,
            },
          }}
        >
          <div {...rest}>{children}</div>
        </motion.div>
      )}
    </AnimatePresence>
  );
};
 
export { ResizablePanel, ResizablePanelContent };

Update the import paths to match your project setup.