1- import React , { FC , ReactElement , cloneElement , useEffect , useRef } from 'react'
2- import { mergeRefs , focusableChildren } from './utils'
1+ import React , { FC , ReactElement , cloneElement , use , useEffect , useRef } from 'react'
2+ import { mergeRefs , focusableChildren , getChildRef } from './utils'
33
44export interface CFocusTrapProps {
55/**
@@ -146,7 +146,10 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
146146
147147if ( elements . length === 0 ) {
148148container . focus ( { preventScroll :true } )
149- } else if ( lastTabNavDirectionRef . current === 'backward' ) {
149+ return
150+ }
151+
152+ if ( lastTabNavDirectionRef . current === 'backward' ) {
150153elements . at ( - 1 ) ?. focus ( { preventScroll :true } )
151154} else {
152155elements [ 0 ] . focus ( { preventScroll :true } )
@@ -161,20 +164,37 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
161164tabEventSourceRef . current = container
162165lastTabNavDirectionRef . current = event . shiftKey ?'backward' :'forward'
163166
164- if ( ! _additionalContainer ) {
165- return
166- }
167-
168167const containerElements = focusableChildren ( container )
169- const additionalElements = focusableChildren ( _additionalContainer )
168+ const additionalElements = _additionalContainer ? focusableChildren ( _additionalContainer ) : [ ]
170169
171170if ( containerElements . length === 0 && additionalElements . length === 0 ) {
172171// No focusable elements, prevent tab
173172event . preventDefault ( )
174173return
175174}
176175
176+ const focusableElements = [ ...containerElements , ...additionalElements ]
177+
178+ const firstFocusableElement = focusableElements [ 0 ] as HTMLElement
179+ const lastFocusableElement = focusableElements . at ( - 1 ) as HTMLElement
177180const activeElement = document . activeElement as HTMLElement
181+
182+ if ( event . shiftKey && activeElement === firstFocusableElement ) {
183+ event . preventDefault ( )
184+ lastFocusableElement . focus ( )
185+ return
186+ }
187+
188+ if ( ! event . shiftKey && activeElement === lastFocusableElement ) {
189+ event . preventDefault ( )
190+ firstFocusableElement . focus ( )
191+ return
192+ }
193+
194+ if ( ! _additionalContainer ) {
195+ return
196+ }
197+
178198const isInContainer = containerElements . includes ( activeElement )
179199const isInAdditional = additionalElements . includes ( activeElement )
180200
@@ -245,7 +265,12 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
245265
246266// Attach our ref to the ONLY child — no extra wrappers
247267const onlyChild = React . Children . only ( children )
248- const childRef = ( onlyChild as React . ReactElement & { ref ?:React . Ref < HTMLElement > } ) . ref
268+
269+ // Handle different ref access patterns between React versions
270+ // React 19+: ref is accessed via element.props.ref
271+ // React 18 and earlier: ref is accessed via element.ref
272+ const childRef :React . Ref < HTMLElement > | undefined = getChildRef ( onlyChild )
273+
249274const mergedRef = mergeRefs ( childRef , ( node :HTMLElement | null ) => {
250275containerRef . current = node
251276} )