I have index.html
<body>
<div id="portal"></div>
<div id="root"></div>
</body>
and want to use the component below in separate portal div than root div,
import React from 'react';
const portalDiv = document.getElementById('portal');
function Portal1(props) {
return ReactDOM.createPortal(
<div>
{props.children}
<div/>,
portalDiv); //here
}
export default Portal1;
But I am getting this error, Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element'. Type 'null' is not assignable to type 'Element'.ts(2345) in VScode.
I am using Typescript. Please help.
Since getElementById possibly returns null. So you just simply check before using like:
function Portal1({ children }) {
return portalDiv ? ReactDOM.createPortal(<>{children}</>, portalDiv) : null;
}
getElementById can return null, but createPortal doesn't accept null.
If you know the portal div will exist, make the code explicit about that:
const portalDiv = document.getElementById('portal');
if (!portalDiv) {
throw new Error("The element #portal wasn't found");
}
That will allow TypeScript to narrow the type of the constant, removing the | null part of the type. It also gives you a nice proactive warning if someone changes things such that the div isn't there when this code runs anymore.
Other people have answered that you should add a null-check, but Typescript also has a non-null assertion that you can use when you are sure that the value is never null by adding the ! operator to the end of your statement:
const portalDiv = document.getElementById('#your-element')!;
I think the best solution to this is not to make it either null or HTMLDIVElement but rather in the use-case try to let typescript know that the DivElement might be empty at the moment, but you will take responsibility of it by just using "!" symbol.
Code sample below:
import React, {useEffect} from 'react';
import ReactDOM from 'react-dom';
import './modal-portlet.style.scss';
const modalRoot = document.getElementById('modalRoot');
type Props = {
children: JSX.Element;
};
const ModalPortlet: React.FC<Props> = ({children}): JSX.Element => {
const divContainer = window.document.createElement('div');
divContainer.setAttribute('class', 'modal-container');
useEffect(() => {
/**********
* immediately the component mount append @divContainer as the childNode of @modalRoot in the DOM
**********/
modalRoot!.appendChild(divContainer);
return () => {
modalRoot!.removeChild(divContainer);
};
});
/************
* return the createPortal api that takes the children(JSX) and inject it into @divContainer which is already a childNode of @modalRoot
************/
return <>{ReactDOM.createPortal(children, divContainer)}</>;
};
export default ModalPortlet;
So I dont know if anyone is still having this problem but there's an easier and straightforward solution to this.
simply declare the modal element with "as" keyword
const modalRoot = document.getElementById("modal-root") as HTMLElement;
This removes the error.
I suggest looking through this great react-typescript cheatsheet.
https://github.com/typescript-cheatsheets/react
I was also facing same error so I tried few different ways but the one that worked for me is handling null condition
i.e. const portalDiv = document.getElementById('portal')!;