Skip to content

React 19 Compatibility: CFocusTrap uses deprecated element.ref access #445

@nicmart-dev

Description

@nicmart-dev

CoreUI React 5.9.0 is not fully compatible with React 19 due to deprecated element.ref access in the CFocusTrap component. This causes console warnings and will break in future React versions.

Environment

  • React: 19.1.1
  • React DOM: 19.1.1
  • CoreUI React: 5.9.0
  • CoreUI Core: 5.4.3
  • Node: 18+
  • Browser: Chrome/Firefox (latest)

Error Message

FormModal.js:85 Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.

Stack Trace

CFocusTrap @ CFocusTrap.js:154
CModal @ CModal.js:96
FormModal @ FormModal.js:85

Root Cause Analysis

After investigating the CoreUI React source code, we identified the issue in the CFocusTrap component:

Location 1: src/components/focus-trap/CFocusTrap.tsx (Line 248)

// ❌ Deprecated in React 19
const childRef = (onlyChild as React.ReactElement & { ref?: React.Ref<HTMLElement> }).ref

Location 2: dist/cjs/components/focus-trap/CFocusTrap.js (Line 154)

// ❌ Deprecated in React 19
const childRef = onlyChild.ref;

React 19 removed direct element.ref access. Refs should now be accessed through element.props.ref.

Affected Components

  • CFocusTrap (directly)
  • CModal (uses CFocusTrap)
  • COffcanvas (uses CFocusTrap)
  • Any component using modals or offcanvas

Steps to Reproduce

  1. Create a new React 19 app
  2. Install CoreUI React 5.9.0:
    npm install @coreui/[email protected]
  3. Create a simple modal component:
    import { CModal, CModalHeader, CModalBody, CButton } from '@coreui/react';
    
    function App() {
      const [visible, setVisible] = useState(false);
      
      return (
        <>
          <CButton onClick={() => setVisible(true)}>Open Modal</CButton>
          <CModal visible={visible} onClose={() => setVisible(false)}>
            <CModalHeader>Test Modal</CModalHeader>
            <CModalBody>Content</CModalBody>
          </CModal>
        </>
      );
    }
  4. Run the app and open the modal
  5. Check browser console for React 19 warning

Proposed Solution

Replace deprecated element.ref access with React 19 compatible element.props.ref:

TypeScript Source (src/components/focus-trap/CFocusTrap.tsx):

  // Attach our ref to the ONLY child — no extra wrappers
  const onlyChild = React.Children.only(children)
- const childRef = (onlyChild as React.ReactElement & { ref?: React.Ref<HTMLElement> }).ref
+ // React 19 compatibility: access ref through props instead of deprecated element.ref
+ const childRef = onlyChild.props.ref
  const mergedRef = mergeRefs(childRef, (node: HTMLElement | null) => {
    containerRef.current = node
  })

Compiled JavaScript (dist/cjs/components/focus-trap/CFocusTrap.js):

  // Attach our ref to the ONLY child — no extra wrappers
  const onlyChild = React.Children.only(children);
- const childRef = onlyChild.ref;
+ // React 19 compatibility: access ref through props instead of deprecated element.ref
+ const childRef = onlyChild.props.ref;
  const mergedRef = utils.mergeRefs(childRef, (node) => {
    containerRef.current = node;
  });

Workaround

Until this is fixed in CoreUI, users can apply a patch using patch-package:

  1. Install patch-package:

    npm install --save-dev patch-package postinstall-postinstall
  2. Modify the files as shown above

  3. Create the patch:

    npx patch-package @coreui/react
  4. Add to package.json:

    {
      "scripts": {
        "postinstall": "patch-package"
      }
    }

The patch will automatically apply on npm install.

Testing

We have tested this fix in production and confirmed:

  • ✅ React 19 warnings eliminated
  • ✅ Modal functionality fully preserved
  • ✅ Focus management working correctly
  • ✅ Keyboard navigation (Tab, Escape) working
  • ✅ All existing features functional
  • ✅ No performance impact

Additional Context

This is a breaking change in React 19 as documented in the React 19 Upgrade Guide:

In React 19, ref is treated as a regular prop, and accessing element.ref is deprecated. Use element.props.ref instead.

References

Would You Like Help?

We have a working patch and would be happy to submit a PR if that would be helpful. We've tested this fix thoroughly in our production application.


Note: This issue affects all users upgrading to React 19. An official fix would greatly benefit the CoreUI community.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions