Help with Panel + React + MaterialUI

Hello, I’m trying to combine Panel + React v18 + MaterialUI as shown below, but the result is a button with plain HTML style instead of a Material styled button (see screenshot at the end). What am I missing in the code below to get it right?

import panel as pn
import param

pn.extension()

class Hello(pn.reactive.ReactiveHTML):
    clicks = param.Number(default=0)
    
    _template = """<div id="mywidget"></div>"""
    
    _scripts = {
        "render": """
            const root = ReactDOM.createRoot(mywidget);
            root.render(
                React.createElement(
                    MaterialUI.Button, {
                        variant: "contained", 
                        color: "primary", 
                        children: "Hello", 
                        onClick: () => {data.clicks = data.clicks + 1}
                    }
                )
            )
        """,
    }

    __javascript__ = [
        "https://unpkg.com/react@latest/umd/react.development.js",
        "https://unpkg.com/react-dom@latest/umd/react-dom.development.js",
        "https://unpkg.com/@mui/material@latest/umd/material-ui.development.js"
    ]

Hello()

OK, the code above works. I had to shut down the Jupyter Notebook server and then try again.

2 Likes

Hi

I’ve tried to run the code in a server context with Panel 1.2.3. But I cannot get it styled. It looks like

image

Does React + MaterialUI actually work with Panel 1.x? I’ve found indications that it does not in Support Shadow DOM · Issue #17473 · mui/material-ui (github.com). It seems React and MaterialUI does not support ShadowDOM which is used by Panel 1.x/ Bokeh 3.x.

import panel as pn
import param

pn.extension()

class Hello(pn.reactive.ReactiveHTML):
    clicks = param.Number(default=0)
    
    _template = """<div id="mywidget"></div>"""
    
    _scripts = {
        "render": """
            const root = ReactDOM.createRoot(mywidget);
            root.render(
                React.createElement(
                    MaterialUI.Button, {
                        variant: "contained", 
                        color: "primary", 
                        children: "Hello", 
                        onClick: () => {data.clicks = data.clicks + 1}
                    }
                )
            )
        """,
    }

    __javascript__ = [
        "https://unpkg.com/react@latest/umd/react.development.js",
        "https://unpkg.com/react-dom@latest/umd/react-dom.development.js",
        "https://unpkg.com/@mui/material@latest/umd/material-ui.development.js"
    ]

Hello().servable()

I’ve found something here that might help

Shadow DOM - Material UI (mui.com)

I thought the below would work, but it still does not add styles

import panel as pn
import param

pn.extension()

class Hello(pn.reactive.ReactiveHTML):
    clicks = param.Number(default=0)
    
    _template = """<style id="emotionRoot"></style><div id="mywidget"></div>"""
    
    _scripts = {
        "render": """
            const {
                cache
            } = createEmotion({
                key: 'css',
                prepend: true,
                container: emotionRoot,
            })
            const {CacheProvider}=emotionReact
            const button = React.createElement(
                MaterialUI.Button, {
                    variant: "contained", 
                    color: "primary", 
                    children: "Hello", 
                    onClick: () => {data.clicks = data.clicks + 1}
                }
            )
            const root = ReactDOM.createRoot(mywidget);
            root.render(
                React.createElement(CacheProvider, {value: cache}, button)
            );
        """,
    }

    __javascript__ = [
        "https://unpkg.com/react@latest/umd/react.development.js",
        "https://unpkg.com/react-dom@latest/umd/react-dom.development.js",
        "https://unpkg.com/@mui/material@latest/umd/material-ui.development.js",
        "https://unpkg.com/@emotion/react@11.10.0/dist/emotion-react.umd.min.js",
        "https://unpkg.com/@emotion/css@11.10.0/create-instance/dist/emotion-css-create-instance.umd.min.js"
    ]

Hello().servable()

It would be great if MaterialUI worked with Panel v1 as it did with the previous version. Thanks for reviving this issue, Marc.

1 Like

Yeah it is a very unfortunate limitation. It really limits what libraries we can combine with Panel. It is also often not clear if something is going to work. Maybe it is a question for Bokeh but it would be nice to be able to opt out of using shadow doms for selected components.