Panel Material UI Announcement

announcement
panel
Announcing the release of panel-material-ui, a new extension that wraps Material UI components in Panel.
Author

Philipp Rudiger

Published

May 13, 2025

Today we’re very excited to introduce panel-material-ui, a Panel extension that provides a set of modern components and a cohesive design system built upon Material UI. It is fully compatible with your existing Panel code.

We will start using it in production now, which means you can expect this extension to mature rapidly. Our goal is to replace the existing Panel components with panel-material-ui components in a Panel 2.0 release.

Try it out today with:

pip install panel-material-ui

or:

conda install conda-forge::panel-material-ui

Why?

We have been building Panel for almost 7 years now. Today, it powers dashboards, AI workflows, and data applications across research and industry, with over 1.2 million downloads per month. At the same time one piece of feedback we’ve gotten over and over was that it was too hard to style Panel components.

So we set out to build a comprehensive, consistent, and API compatible set of components, replacing the existing Panel implementations. We wanted to make sure we maintained compatibility with existing Panel components while exposing as many MUI components as possible.

Why MUI in particular, you might ask? We wanted to build on a library that has:

  • Maturity: MUI is one of the most widely used React component libraries, with strong community support and robust documentation.
  • Consistent Design: It implements Google’s Material Design system, providing a polished and consistent user experience out of the box.
  • Customizable and themeable: MUI has a well-designed theming system that maps cleanly to how we wanted to style Panel apps.
  • Strong accessibility support: MUI handles many of the hard parts of accessibility for us, giving us a more solid foundation.
  • Component breadth: It includes a wide range of components — from simple buttons to complex layout and navigation elements — that we can gradually wrap and expose in Panel.

But for our (and your) sanity we also wanted a library that would make it easy to create new components. The tight React implementation just made it a joy to build, particularly with AI assistance. This also means creating custom components building on panel-material-ui is a breeze.

How?

With the addition of ESM components, it has finally become straightforward to build custom Panel components. Building on the React integration, I quickly discovered that mapping parameters in Python to React state was a simple problem where LLMs could provide significant assistance. Using a simple prompt, I was able to bootstrap a comprehensive set of components and their respective React implementations. That said, I’ve always been skeptical of fully auto-generated component wrappers. While promising in theory, the UX of a purely automated wrapper library inevitably suffers, and the initial AI-generated component set was no exception.

Once the basic structure was in place, we methodically reviewed, cleaned up, and documented each component in detail. At this point, I’d like to extend special thanks to Thuy Do and Marc Skov Madsen for their invaluable contributions in writing tests, creating documentation, and providing feedback throughout the process.

What can it do?

Okay, so what can it actually do? Yes, we’ve added 70+ components, and they’re all consistently styled, but what else is possible now that wasn’t before?

Theming & Styling

In the past Panel had introduced a so called Design. We build on that here but for the most part only use that system to ensure that the theme defined in panel-material-ui flows down to standard Panel components. Let’s briefly define our technology:

  • Design: The overall set of CSS stylesheets, component defaults that align an application with a particular design system.
  • Theme: A theme in Panel defines the configuration of default color settings in both light (default) and dark mode.
  • Styling: Applying one-off modications to a specific components.

In panel-material-ui the main entrypoint for theming that you need to care about is the theme_config parameter, present on all Material components. It makes it easy to configure the default colors, typography and more, either globally or differentially for dark and light themes. Thanks to inheritance the theme_config can be applied on a parent component and will flow down to all its children:

from panel_material_ui import Card, Button, FloatSlider

Card(
    FloatSlider(label="Child Slider", color="primary"),
    Button(label="Child Button", color="primary"),
    title="Parent Card",
    theme_config={
        "palette": {
            "primary": {"main": "#d219c9"},
        },
        "typography": {
            "fontFamily": "monospace"
        }
    },
    margin=10
)

This approach allows controlling the theme across an entire application or, thanks to inheritance, overriding the theme for some part of an application, e.g. to apply custom styles in the header or sidebar.

For one-off customizations the sx parameter provides fine-grained control over every aspect of an component:

FloatSlider(
    label="My Styled Slider",
    margin=20,
    sx={
        ".MuiFormLabel-root": {"fontFamily": "monospace"},
        ".MuiSlider-thumb": {
            "borderRadius": 0  # square
        },
        ".MuiSlider-thumb:hover": {
            "background-color": "deeppink"
        }
    }
)

Branding

Using the above theming and styling and the Page element its now simple to create branded apps:

branding-example

Here is another example of a highly customized dashboard:

custom-dashboard

Dark Mode

In Panel theming happened on the backend, i.e. if you toggled between the default (light) and the dark theme the application would have to re-run in order to ensure the updated theming would be propagated. In panel-material-ui theming happens client-side. By using the ThemeToggle or Page components in your app you enter managed theming mode where the theme is controlled globally and styles are updated dynamically.

toggle = pmui.ThemeToggle(styles={'margin-left': 'auto'})
plot = df.hvplot.scatter(
    'bill_length_mm', 'bill_depth_mm', c='species', responsive=True, min_height=300
)
table = pn.widgets.Tabulator(df.iloc[:, :5], page_size=5, sizing_mode='stretch_width')

pmui.Paper(toggle, plot, table)

Responsiveness

While Panel could be configured to provide a good mobile experience, it was previously quite cumbersome. In panel-material-ui we are paying attention to the mobile experience: the Page automatically adapts to smaller screen by switching the sidebar, the Grid component allows configuring the layout per breakpoint, and the BreakpointSwitcher allows dynamically switching between different components depending on the breakpoints.

Try resizing the output:

from panel_material_ui import Grid

item = lambda content: pmui.Paper(
    content, elevation=5, height=100, sizing_mode="stretch_width"
)

small = pmui.Select(options=pmui.COLORS)
large = pmui.RadioButtonGroup(options=pmui.COLORS)

switcher = pmui.BreakpointSwitcher(
    media_query='(min-width: 800px)',
    small=small,
    large=large,
)

grid = Grid(
    Grid(item('Foo'), size={"sm": 8, "xs": 12}),
    Grid(item('Bar'), size={"sm": 4, "xs": 12}),
    Grid(item('Baz'), size={"sm": 4, "xs": 12}),
    Grid(item('Qux'), size={"sm": 8, "xs": 12}),
    container=True, margin=10, spacing=2
)

pmui.Column(switcher, grid)

Note how the switcher toggles between large and small implementations and the grid adjusts to the configured breakpoints.

Compatibility

Above, we mentioned that panel-material-ui has full compatibility with Panel, but what does that actually mean? The goal from the very beginning was to provide a set of components that could be drop-in replacements for existing Panel components, this means that you should be able to change the imports and with a few minor exceptions the panel-material-ui component should behave just like the original Panel one. The idea being that the transition to panel-material-ui should be as easy as possible and that when we eventually replace the original Panel components as part of the Panel 2.0 release, there will not be a major transition either. Compatibility also means you can mix-and-match regular panel and panel-material-ui components as you see fit.

What’s next?

With this being the first public release, our work of course isn’t done. Creating, polishing documenting and testing 70+ components is a pretty monumental effort, even with AI assistance. There will be issues. But we are starting to use the library in production immediately and we expect to fix issues as soon as we uncover them. Thanks to the simplicity of the approach, resolving issues will be much simpler than the complex build chain required to develop the original components in Bokeh and Panel.

As we incubate these components in the panel-material-ui library we are aiming to reach stability and maturity in the coming months and eventually aim to replace the existing components in Panel with this more modern implementation as part of the Panel 2.0 release by the end of the year.

For now we would love for you to try it out, hear your feedback and see what you build with it.

Back to top