heroui-inc/heroui · warning
Ref was not connected to DOM element returned by custom `ren
Error message
Ref was not connected to DOM element returned by custom `render` function. Did you forget to pass through or merge the `ref`?
What it means
When a component's `render` prop replaces the default DOM element, HeroUI merges its forwarded ref into the rendered output via mergeRefs. A layout effect checks (in non-production builds) that the ref actually got attached; if the custom render result never receives the ref, the internal element reference stays null and this console warning fires, because features like focus, measurement, or positioning that rely on the ref will silently break.
Source
Thrown at packages/react/src/utils/dom.tsx:45
* * Only a single root DOM element can be rendered (no fragments).
* * You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
*/
render?: DOMRenderFunction<E, T>;
}
// eslint-disable-next-line react-refresh/only-export-components
function DOMElement(
ElementType: string,
props: DOMRenderProps<any, any> & AllHTMLAttributes<HTMLElement> & {ref?: React.Ref<HTMLElement>},
) {
const {ref: forwardedRef, render, ...otherProps} = props;
const elementRef = useRef<HTMLElement | null>(null);
const ref = useMemo(() => mergeRefs(forwardedRef, elementRef), [forwardedRef, elementRef]);
useLayoutEffect(() => {
if (typeof process !== "undefined" && process.env?.["NODE_ENV"] !== "production" && render) {
if (!elementRef.current) {
console.warn(
"Ref was not connected to DOM element returned by custom `render` function. Did you forget to pass through or merge the `ref`?",
);
}
}
}, [ElementType, render]);
const domProps: any = {...otherProps, ref};
if (render) {
return render(domProps, undefined);
}
return <ElementType {...domProps} />;
}
type DOMComponents = {
[E in keyof React.JSX.IntrinsicElements]: (
props: DOMRenderProps<E, any> & React.JSX.IntrinsicElements[E],View on GitHub (pinned to 7546fff813)
Solutions
- Pass all props through: render={(props) => <MyDiv {...props} />} so ref and other injected props reach the DOM
- If the render target is your own component, wrap it in React.forwardRef and attach the ref to its root DOM node
- Ensure any intermediate wrapper forwards refs (avoid plain function components that discard ref in React 19- setups)
Example fix
// before
<TooltipTrigger render={(props) => <StyledSpan>{props.children}</StyledSpan>} />
// after
<TooltipTrigger render={(props) => <StyledSpan {...props} />} /> Defensive patterns
Strategy: validation
Validate before calling
// Always forward the full props object to the render target so ref is included:
<Comp render={(props) => <Custom {...props} />} />; Type guard
// For custom components, ensure forwardRef is used:
const Custom = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(
(props, ref) => <span ref={ref} {...props} />,
); Prevention
- Always spread the full render props onto the custom element
- Use forwardRef (or ref-accepting components) for render targets
- Test render-prop customizations in dev builds to catch the warning early
When it happens
Trigger: Passing render={(props) => <MyDiv />} or render={<MyDiv />} where MyDiv does not accept/forward props.ref to its DOM element; forwarding only some props (e.g. spreading {...rest} but omitting ref, or using a component that doesn't forward refs).
Common situations: Using a styled custom element or non-forwardRef function component as the render target; memoized wrappers that drop the ref; converting render props from spread syntax to explicit props and forgetting ref.
Related errors
- useCalendarOrRangeState must be used within a <Calendar> or
- useYearPicker must be used within a <Calendar> or <RangeCale
- CalendarYearPicker trigger components must be used within <C
- CalendarYearPicker components must be used within <CalendarY
- [HeroUI ColorSlider] Invalid combination: channel="${channel
AI-assisted analysis of heroui-inc/heroui@7546fff813 (2026-08-28).
Data as JSON: /api/errors/b92abc6e9775a9f9.
Report an issue: GitHub.