Skip to content

Commit faf718f

Browse files
authored
fix(react): avoid React 19 element ref warning (#1815)
1 parent ec13a62 commit faf718f

1 file changed

Lines changed: 25 additions & 4 deletions

File tree

  • packages/react/src/components/primitives

packages/react/src/components/primitives/slot.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,15 @@ const SlotClone = React.forwardRef<any, SlotCloneProps>((props, forwardedRef) =>
6666
const { children, ...slotProps } = props;
6767

6868
if (React.isValidElement(children)) {
69-
return React.cloneElement<any>(children, {
70-
...mergeProps(slotProps, children.props as any),
71-
ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,
72-
});
69+
const childrenRef = getElementRef(children),
70+
props = mergeProps(slotProps, children.props as any);
71+
72+
// Do not pass `ref` to React.Fragment for React 19 compatibility.
73+
if (children.type !== React.Fragment) {
74+
props.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
75+
}
76+
77+
return React.cloneElement<any>(children, props);
7378
}
7479

7580
return React.Children.count(children) > 1 ? React.Children.only(null) : null;
@@ -126,6 +131,22 @@ function mergeProps(slotProps: AnyProps, childProps: AnyProps) {
126131
return { ...slotProps, ...overrideProps };
127132
}
128133

134+
function getElementRef(element: React.ReactElement) {
135+
// React <=18 in DEV warns when reading `props.ref`, so read from the element instead.
136+
let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get,
137+
mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
138+
139+
if (mayWarn) return (element as any).ref;
140+
141+
// React 19 in DEV warns when reading `element.ref`, so read from props instead.
142+
getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;
143+
mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning;
144+
145+
if (mayWarn) return (element.props as { ref?: React.Ref<unknown> }).ref;
146+
147+
return (element.props as { ref?: React.Ref<unknown> }).ref || (element as any).ref;
148+
}
149+
129150
const Root = Slot;
130151

131152
export { Slot, Slottable, Root };

0 commit comments

Comments
 (0)