notistack items not rendered into provided domRoot container

1.1k Views Asked by At

My goal is it to display the notisstack snackbar items inside a div-container which is readable by screenreaders. Therefore I wanted to use the domRoot property of the SnackbarProvider.

I'am using notistack 3.0.7

My Problem is now, that the div-container element is rendered but not used as the root for my snackbaritem. I have only defined a single SnackbarProvider.

dom screenshot

index.tsx

const SnackbarProviderWrapper = () => {

    const alertContainer = React.createElement('div', {
        "aria-live": "assertive",
        className: "alert-container"
    }) as unknown as HTMLElement

    return (
        <SnackbarProvider anchorOrigin={{vertical: "bottom", horizontal: "center"}}
                          domRoot={alertContainer}
                      >
            <App/>
            {alertContainer}
        </SnackbarProvider>
    )
}


ReactDOM.render(
    <React.StrictMode>
                <SnackbarProviderWrapper/>
    </React.StrictMode>,
    document.getElementById('root')
);
1

There are 1 best solutions below

0
On

Ok I found a workaround solution. It is no exceptional "dirty" but not clean either.

First I moved the SnackbarProvider to a component, in my case the App component to have access to hooks. Than I used a component for my container instead of React.createElement(...). This component forwards its div-Element via forwardRef. Finaly we manage the Element via a useState() hook.

/**
 * This is the Element that will be used as a container for all notistack snackbar items
 */
const AlertContainer = React.forwardRef<HTMLDivElement>((props, ref) => (
    <div ref={ref} className="alert-container" aria-live={"assertive"}>
        {props.children}
    </div>
));

function App() {
    const [alertContainer, setAlertContainer] = useState<HTMLDivElement | null>(null)

    return (
        <>
            <AlertContainer ref={setAlertContainer}/>
            {alertContainer ?
                <SnackbarProvider anchorOrigin={{vertical: "bottom", horizontal: "center"}}
                                  domRoot={alertContainer}>
                    <main/>
                </SnackbarProvider>
                : null /* we must have this conditon to render the DOM once so our AlertContainer is present*/}
        </>
    );
}

You might ask why not use a useRef() hook? That is because the Tree must render at least once before using the container component. For this reason we have also added the condition that returns null on the first render. If we don't have this our AlertContainer componente is not yet present in the DOM and domRoot will be null.

It is strange that notistack expects an already initialized HTMLElement for the property domRoot. This prohibits us from using a regular ref here. This is especially strange since there is no need to use an existing DOM element. The element must be present when an Alert/SnackbarItem must be displayed, not before.