11import type { Variants } from "framer-motion" ;
2- import type { ReactNode } from "react" ;
32import type { UseAccordionItemProps } from "./use-accordion-item" ;
3+ import type { ReactNode } from "react" ;
44
55import { forwardRef } from "@heroui/system" ;
6- import { useMemo } from "react" ;
6+ import { useMemo , useRef , useEffect } from "react" ;
77import { ChevronIcon } from "@heroui/shared-icons" ;
88import { AnimatePresence , LazyMotion , m , useWillChange } from "framer-motion" ;
99import { TRANSITION_VARIANTS } from "@heroui/framer-utils" ;
@@ -31,6 +31,8 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
3131 keepContentMounted,
3232 disableAnimation,
3333 motionProps,
34+ scrollOnOpen,
35+ transitionDuration,
3436 getBaseProps,
3537 getHeadingProps,
3638 getButtonProps,
@@ -41,6 +43,22 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
4143 } = useAccordionItem ( { ...props , ref} ) ;
4244
4345 const willChange = useWillChange ( ) ;
46+ const contentRef = useRef < HTMLDivElement > ( null ) ;
47+
48+ // Handle scrolling to content when opened
49+ useEffect ( ( ) => {
50+ if ( isOpen && scrollOnOpen && contentRef . current ) {
51+ const content = contentRef . current ;
52+
53+ // Wait for animation to start
54+ setTimeout ( ( ) => {
55+ content . scrollIntoView ( {
56+ behavior : "smooth" ,
57+ block : "nearest" ,
58+ } ) ;
59+ } , 50 ) ;
60+ }
61+ } , [ isOpen , scrollOnOpen ] ) ;
4462
4563 const indicatorContent = useMemo < ReactNode > ( ( ) => {
4664 if ( typeof indicator === "function" ) {
@@ -57,15 +75,33 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
5775 const content = useMemo ( ( ) => {
5876 if ( disableAnimation ) {
5977 if ( keepContentMounted ) {
60- return < div { ...getContentProps ( ) } > { children } </ div > ;
78+ return (
79+ < div ref = { contentRef } { ...getContentProps ( ) } >
80+ { children }
81+ </ div >
82+ ) ;
6183 }
6284
63- return isOpen && < div { ...getContentProps ( ) } > { children } </ div > ;
85+ return (
86+ isOpen && (
87+ < div ref = { contentRef } { ...getContentProps ( ) } >
88+ { children }
89+ </ div >
90+ )
91+ ) ;
6492 }
6593
6694 const transitionVariants : Variants = {
67- exit : { ...TRANSITION_VARIANTS . collapse . exit , overflowY : "hidden" } ,
68- enter : { ...TRANSITION_VARIANTS . collapse . enter , overflowY : "unset" } ,
95+ exit : {
96+ ...TRANSITION_VARIANTS . collapse . exit ,
97+ overflowY : "hidden" ,
98+ transition : { duration : transitionDuration ? transitionDuration / 1000 : 0.3 } ,
99+ } ,
100+ enter : {
101+ ...TRANSITION_VARIANTS . collapse . enter ,
102+ overflowY : "unset" ,
103+ transition : { duration : transitionDuration ? transitionDuration / 1000 : 0.3 } ,
104+ } ,
69105 } ;
70106
71107 return keepContentMounted ? (
@@ -82,7 +118,9 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
82118 } }
83119 { ...motionProps }
84120 >
85- < div { ...getContentProps ( ) } > { children } </ div >
121+ < div ref = { contentRef } { ...getContentProps ( ) } >
122+ { children }
123+ </ div >
86124 </ m . section >
87125 </ LazyMotion >
88126 ) : (
@@ -101,13 +139,15 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
101139 } }
102140 { ...motionProps }
103141 >
104- < div { ...getContentProps ( ) } > { children } </ div >
142+ < div ref = { contentRef } { ...getContentProps ( ) } >
143+ { children }
144+ </ div >
105145 </ m . section >
106146 </ LazyMotion >
107147 ) }
108148 </ AnimatePresence >
109149 ) ;
110- } , [ isOpen , disableAnimation , keepContentMounted , children , motionProps ] ) ;
150+ } , [ isOpen , disableAnimation , keepContentMounted , children , motionProps , transitionDuration ] ) ;
111151
112152 return (
113153 < Component { ...getBaseProps ( ) } >
0 commit comments