I have this React component where I'm trying to move focus to a specific div after the component has finished rendering.
I've tried debugging in my browser and the containerRef
is never set. When I pause execution on the line that reads: if (containerRef.current) {
I can also see that the component has not been rendered yet. And the component is currently only rendered once (passing hardcoded data in Storybook, but also tried mocking it inside the real app, thinking that some wrapper component in Storybook might be triggering the hook somehow).
Any suggestions why this might be?
export function DuplicateSelect(props: DuplicateSelectProps) {
const containerRef = useRef(null);
useEffect(() => {
if (containerRef.current) {
containerRef.current.focus();
}
});
return (
<Overlay isOpen={true}>
<div className="flex-center">
<Card className="duplicate-select" elevation={1}>
<div
className="duplicate-select-options"
tabIndex={0}
ref={containerRef}
>
{props.results.map((result) => (
<Item data={result} />
))}
</div>
</Card>
</div>
</Overlay>
);
}
Made a prototype in Codesandbox and that works fine: https://codesandbox.io/s/damp-dust-4xiv0
I am using Blueprint.js as a UI library and on further investigation I discovered that the problem was due to the <Overlay>
component rendering inside a portal. There was a prop to disable this behaviour and that solved the problem. Seems like maybe refs break when using portals?
export function DuplicateSelect(props: DuplicateSelectProps) {
const containerRef = useRef(null);
useEffect(() => {
if (containerRef.current) {
containerRef.current.focus();
}
});
return (
<Overlay isOpen={true} usePortal={false} >
<div className="flex-center">
<Card className="duplicate-select" elevation={1}>
<div
className="duplicate-select-options"
tabIndex={0}
ref={containerRef}
>
{props.results.map((result) => (
<Item data={result} />
))}
</div>
</Card>
</div>
</Overlay>
);
}