Skip to content

Commit 0866e13

Browse files
committed
fix(react): avoid React 19 element ref warning
1 parent b0f119c commit 0866e13

1 file changed

Lines changed: 19 additions & 1 deletion

File tree

  • packages/react/src/components/primitives

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ const SlotClone = React.forwardRef<any, SlotCloneProps>((props, forwardedRef) =>
6666
const { children, ...slotProps } = props;
6767

6868
if (React.isValidElement(children)) {
69+
const childrenRef = getElementRef(children);
70+
6971
return React.cloneElement<any>(children, {
7072
...mergeProps(slotProps, children.props as any),
71-
ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,
73+
ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef,
7274
});
7375
}
7476

@@ -126,6 +128,22 @@ function mergeProps(slotProps: AnyProps, childProps: AnyProps) {
126128
return { ...slotProps, ...overrideProps };
127129
}
128130

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

131149
export { Slot, Slottable, Root };

0 commit comments

Comments
 (0)