[RAC] inputRef is undefined in Textfield
Provide a general summary of the issue here
Textfield is providing an InputContext but when consuming it, the inputRef is undefined
I am consuming it like this
const { ref } = useSlottedContext(InputContext)
const Demo = ()=> {
return (
<TextField>
<Input />
<Btn />
</TextField>
}
const Btn = () => {
const inputCtx = useSlottedContext(InputContext)
return (
<Button onPress={()=>{console.log(inputCtx?.ref?.current))>Log</Button>
}
๐ค Expected Behavior?
Expecting to ref to return the actual ref of the รnput in the TextField component
๐ฏ Current Behavior
Currently the ref is undefined
๐ Possible Solution
No response
๐ฆ Context
No response
๐ฅ๏ธ Steps to Reproduce
https://codesandbox.io/p/sandbox/rac-textfield-input-ref-issue-d93cvl
Version
1.2
What browsers are you seeing the problem on?
Chrome
If other, please specify.
No response
What operating system are you using?
Windows
๐งข Your Company/Team
No response
๐ท Tracking Issue
No response
It doesn't look like we are sending a ref you'd be able to access in the way you expect anyways. Can I ask more about what you're trying to accomplish? Could you do something along these lines instead?
let CustomContext = createContext({ ref: null });
const Field = (props) => {
let inputRef = useRef(null);
return (
<CustomContext.Provider value={{ ref: inputRef }}>
<TextField defaultValue="with textfield">
<Input ref={inputRef} />
<LogButton />
</TextField>
</CustomContext.Provider>
);
};
const LogButton = (props) => {
let { ref } = useContext(CustomContext);
return (
<Button
onPress={() => {
console.log(ref?.current);
}}
>
Log ref
</Button>
);
};
I think you're wrong
ref: https://github.com/adobe/react-spectrum/blob/main/packages/react-aria-components/src/TextField.tsx
[InputContext, {...inputProps, ref: inputOrTextAreaRef}],
[TextAreaContext, {...inputProps, ref: inputOrTextAreaRef}],
My useCase: i have an <InputWrapper /> component that wraps any input where i need the ref to focus on input element when needed
interface InputWrapperProps
extends Omit<AriaGroupProps, "className" | "prefix">,
VariantProps<typeof inputStyles> {
prefix?: React.ReactNode;
suffix?: React.ReactNode;
loading?: boolean;
loaderPosition?: "prefix" | "suffix";
className?: string;
}
const InputWrapper = React.forwardRef<HTMLDivElement, InputWrapperProps>(
(
{
className,
size,
variant,
loading,
prefix,
suffix,
loaderPosition = "suffix",
multiline = false,
...props
},
ref
) => {
const { isInvalid } = React.useContext(AriaFieldErrorContext);
const inputProps = React.useContext(AriaInputContext);
const textAreaProps = React.useContext(AriaTextAreaContext);
const localRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);
const inputRef = inputProps?.ref ?? textAreaProps?.ref ?? localRef; // TODO Fix this
const { root } = inputStyles({
size,
variant: variant ?? (isInvalid ? "danger" : undefined),
multiline,
});
const showPrefixLoading = loading && loaderPosition === "prefix";
const showSuffixLoading = loading && loaderPosition === "suffix";
return (
<Provider
values={[
[AriaInputContext, { ...inputProps, ref: inputRef as React.RefObject<HTMLInputElement> }],
[
AriaTextAreaContext,
{ ...textAreaProps, ref: inputRef as React.RefObject<HTMLTextAreaElement> },
],
]}
>
<AriaGroup
ref={ref}
role="presentation"
className={root({ className })}
{...props}
onPointerDown={(event) => {
const target = event.target as HTMLElement;
if (target.closest("input, button, a")) return;
const input = inputRef.current;
if (!input) return;
requestAnimationFrame(() => {
input.focus();
});
}}
>
{composeRenderProps(props.children, (children) => (
<>
<InputInnerVisual
side="start"
loading={showPrefixLoading}
multiline={multiline}
>
{prefix}
</InputInnerVisual>
{children}
<InputInnerVisual
side="end"
loading={showSuffixLoading}
multiline={multiline}
>
{suffix}
</InputInnerVisual>
</>
))}
</AriaGroup>
</Provider>
);
}
);
InputWrapper.displayName = "InputWrapper";
I think you're wrong
ref: https://github.com/adobe/react-spectrum/blob/main/packages/react-aria-components/src/TextField.tsx
[InputContext, {...inputProps, ref: inputOrTextAreaRef}], [TextAreaContext, {...inputProps, ref: inputOrTextAreaRef}],
Those are defined as a callback ref, it has no 'current' property, therefore, you cannot access it in the way you are expecting. https://github.com/adobe/react-spectrum/blob/0c17289de18041e6f8b99df26a5a3ca922cc5145/packages/react-aria-components/src/TextField.tsx#L70
What you could do though, is merge the ref already on the context with your own ref. Then place that merged ref on the context to propagate it down. https://github.com/adobe/react-spectrum/blob/main/packages/%40react-aria/utils/src/mergeRefs.ts
Okey, it's more clear for me, thank you so much ๐