📣 Dash Mantine Components 2.1.0 Release

:sparkles: What’s New

  • New ModalStack and DrawerStack components
  • Function prop support extended across more components
  • Custom rendering for calendar controls and tree nodes
  • New props for Slider, RangeSlider, and more
  • Based on Mantine 8.1.2

:play_button: Want to Try It Live?

This post shows screenshots only — to explore live examples with code, check out the
:open_book: DMC 2.1.0 Release Announcement on the docs site



:card_index_dividers: New ModalStack and DrawerStack Components

You can now stack multiple modals or drawers using ModalStack or DrawerStack. These components handle z-index layering, focus management, and Escape key behavior for you.



:date: Calendar headerControlsOrder Prop

Calendar-based components (like DatePicker) now support the headerControlsOrder prop, giving you control over the order of header buttons.


:level_slider: Slider domain Prop

The Slider component now accepts a domain prop, letting you set the full allowed range independently from min/max.


↔️ RangeSlider pushOnOverlap Prop

RangeSlider now supports pushOnOverlap — so when thumbs overlap, one can push the other instead of blocking.

The default is True This example shows setting pushOnOverlap=False


:hammer_and_wrench: Additional Props Now Support Functions

In DMC v2.0, we introduced support for passing JavaScript functions to certain props. In v2.1, that support has expanded to cover calendar inputs, AutoComplete, and Tree components.

You can now use functions to:

  • Highlight or disable specific days, months, or years in calendar pickers
  • Customize how AutoComplete options are rendered or filtered
  • Control the rendering of each Tree node — including layout and icons

See the Functions as Props docs for more info, including tips on using AI to help generate the JavaScript functions. Or jump to the table of supported props.

:round_pushpin: Example: Add an indicator to a calendar day

:date: Example: Add styles and disable logic to calendar controls

Use getDayProps, getMonthControlProps, and getYearControlProps to highlight specific dates or disable years and months dynamically.

This example:

  • Highlights every Friday the 13th
  • Disables June and highlights February in the month picker
  • Disables 2026 and highlights 2025 in the year picker




:deciduous_tree: Example: Custom Tree Rendering

Use the renderNode prop in the Tree component to fully control node appearance, including custom icons or layout.


:magnifying_glass_tilted_left: AutoComplete Improvements

Thanks to first-time contributor @ihor-lazariev, AutoComplete now supports:

  • renderOption and filter as function props
  • New clearButtonProps and a new clearable option


:receipt: Other Notable Changes

  • presets for DatePicker: Add predefined date ranges
  • Popover improvements: Better dropdown positioning with dynamic content
  • All components now support the bdrs style prop (border radius)
  • Tooltip now supports the autoContrast prop for better legibility

See the full Mantine 8.1.0 changelog for more.


:high_voltage: Quick Start

If you’re using Dash ≥ 3.0.0, you no longer need to set the React version manually.
If you’re on DMC ≥ 1.2.0, no need to include additional stylesheets like dmc.styles.ALL.

Here’s a minimal starter app:

import dash_mantine_components as dmc
from dash import Dash

app = Dash()

app.layout = dmc.MantineProvider(
    dmc.Alert(
        "Welcome to Dash Mantine Components",
        title="Hello!",
        color="violet",
    )
)

if __name__ == "__main__":
    app.run(debug=True)

:raising_hands: Thank You

Huge thanks to @ihor-lazariev for the AutoComplete improvements in PR #604.

Special thanks to @alexcjohnson for helpful reviews and guidance on this project.

7 Likes

The best days in software development are when you check the Plotly forum and see @AnnMarieW has posted a new DMC update :rocket: Awesome work!

:star_struck: that dmc.:christmas_tree: tho!

5 Likes

Wow @AnnMarieW this update is impressive. I love the ModalStack option and the new customization capabilities of the DMC calendar. Big improvements to the Dash ecosystem.
Thank you :folded_hands:

1 Like


I thought this was pretty neat! wanted to share how I used that new renderOption to provide images in a dmc.Select I’ve been building out:

dashMantineFunctions.js

var dmcfuncs = window.dashMantineFunctions = window.dashMantineFunctions || {};

dmcfuncs.renderProductOption = function ({ option }) {
  const React = window.React;

  // Return React elements instead of DOM elements
  return React.createElement('div', {
    style: {
      display: 'flex',
      alignItems: 'center',
      gap: '12px',
      padding: '4px 0'
    }
  }, [
    // Image container
    React.createElement('div', {
      key: 'img-container',
      style: {
        width: '40px',
        height: '40px',
        borderRadius: '8px',
        overflow: 'hidden',
        flexShrink: '0',
        backgroundColor: '#f3f4f6',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
      }
    },
      option.image
        ? React.createElement('img', {
            src: option.image,
            style: {
              width: '100%',
              height: '100%',
              objectFit: 'cover'
            }
          })
        : React.createElement('svg', {
            width: '24',
            height: '24',
            viewBox: '0 0 24 24',
            fill: 'none',
            stroke: '#9ca3af',
            strokeWidth: '2'
          }, [
            React.createElement('rect', {
              key: 'rect',
              x: '3',
              y: '3',
              width: '18',
              height: '18',
              rx: '2',
              ry: '2'
            }),
            React.createElement('line', {
              key: 'line1',
              x1: '9',
              y1: '9',
              x2: '15',
              y2: '15'
            }),
            React.createElement('line', {
              key: 'line2',
              x1: '15',
              y1: '9',
              x2: '9',
              y2: '15'
            })
          ])
    ),

    // Text container
    React.createElement('div', {
      key: 'text-container',
      style: {
        flex: '1',
        minWidth: '0'
      }
    }, [
      // Product name
      React.createElement('div', {
        key: 'name',
        style: {
          fontSize: '14px',
          fontWeight: '500',
          color: '#111827',
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          textOverflow: 'ellipsis'
        }
      }, option.label),

      // Product description (if exists)
      option.description && React.createElement('div', {
        key: 'desc',
        style: {
          fontSize: '12px',
          color: '#6b7280',
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          textOverflow: 'ellipsis',
          marginTop: '2px'
        }
      }, option.description)
    ].filter(Boolean))
  ]);
};

dash page:

def prepare_product_select_data(products_data):
    """Prepare product data for the select component with grouping by menu category"""
    # Group products by menu category
    grouped_products = {}

    for product in products_data.get('base_products', []):
        menu_category = product['metadata'].get('menu', 'other')

        # Create display label based on category
        category_labels = {
            'appetizer': 'Appetizers',
            'main': 'Main Dishes',
            'pizza': 'Pizzas',
            'desert': 'Desserts',
            'beverage': 'Beverages',
            'other': 'Other Items'
        }

        group_label = category_labels.get(menu_category, 'Other Items')

        if group_label not in grouped_products:
            grouped_products[group_label] = []

        # Get first image or None
        image = product['images'][0] if product['images'] else None

        grouped_products[group_label].append({
            'value': product['id'],
            'label': product['name'],
            'description': product.get('description', ''),
            'image': image
        })

    # Convert to format expected by dmc.Select
    select_data = []
    for group, items in grouped_products.items():
        if items:  # Only add groups that have items
            select_data.append({
                'group': group,
                'items': items
            })

    # Sort groups in a logical order - Fixed typo here
    category_order = ['Appetizers', 'Main Dishes', 'Pizzas', 'Desserts', 'Beverages', 'Other Items']
    select_data.sort(
        key=lambda x: category_order.index(x['group']) if x['group'] in category_order else len(category_order))

    return select_data

# Associated dish for add-ons
                html.Div(
                    [
                        dmc.Select(
                            label="Associated Base Product",
                            placeholder="Select the base product this add-on belongs to",
                            id="new-product-associated-dish",
                            leftSection=DashIconify(icon="tabler:link", width=18),
                            description="Link this add-on to a specific base product",
                            searchable=True,
                            clearable=True,
                            data=[],  # Will be populated by callback
                            renderOption={"function": "renderProductOption"},
                            maxDropdownHeight=400,
                            size="md",
                            styles={
                                "dropdown": {
                                    "padding": "8px",
                                    "border": "1px solid #e5e7eb"
                                },
                                "option": {
                                    "padding": "4px 8px",
                                    "borderRadius": "6px"
                                }
                            },
                            comboboxProps={
                                "shadow": "md",
                                "withinPortal": True
                            }
                        ),
                        dmc.Text(
                            "Tip: Only base products are shown. The add-on will appear as an option when customers order the selected product.",
                            size="xs",
                            c="dimmed",
                            mt="xs"
                        )
                    ],
                    id="associated-dish-container",
                    style={"display": "none"}
                ),
2 Likes

Hey @PipInstallPython - that looks great! Thanks for sharing!

This example demonstrates some advanced features of DMC.

Note that these JavaScript functions are a lot easier to write now with the help of AI.
See the DMC docs for hints on how to do this.:

2 Likes