# 📣 Dash Mantine Components 2.1.0 Release

**URL:** <https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942>\
**Category:** Dash Python\
**Created:** [July 1, 2025, 2:35pm UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942 "2025-07-01T14:35:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [July 1, 2025, 2:35pm UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/1 "2025-07-01T14:35:07Z")

</div>

## ✨ 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](https://mantine.dev/changelog/8-1-0/)

* * *

## ▶ Want to Try It Live?

This post shows screenshots only — to explore live examples with code, check out the  
📖 [DMC 2.1.0 Release Announcement on the docs site](https://www.dash-mantine-components.com/release-2-1-0)

* * *

```auto

```

## 🗂 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.

![](https://github.com/user-attachments/assets/1c74147c-f775-4af0-9715-cb01fe373f46)

```auto

```

* * *

## 📅 Calendar `headerControlsOrder` Prop

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

![](https://github.com/user-attachments/assets/bf3bf4a6-68e8-43c8-a92a-1557eba7bcda)

* * *

## 🎚 Slider domain Prop

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

![](https://github.com/user-attachments/assets/6d33f7d5-5b3f-4763-9954-f13a785868fb)

* * *

## ↔️ 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`

![](https://github.com/user-attachments/assets/e40e5f57-7c5f-4136-91d4-1471d1cb4d51)

* * *

## 🛠 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](https://community.plotly.com/functions-as-props) for more info, including tips on using AI to help generate the JavaScript functions. Or [jump to the table of supported props](https://community.plotly.com/functions-as-props#supported-props-in-v2-1).

### 📍 Example: Add an indicator to a calendar day

![](https://github.com/user-attachments/assets/c5c199c2-8345-46c8-9cd8-4116179a8c06)

### 📅 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

```auto

```

![](https://github.com/user-attachments/assets/b15b17c3-e5fb-4be8-8d72-55de79bfbcfd)

```auto

```

### 🌳 Example: Custom Tree Rendering

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

![](https://github.com/user-attachments/assets/47c62364-9b99-4776-8184-86b64c10b5a0)

* * *

## 🔍 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

![](https://github.com/user-attachments/assets/5d181580-7756-48c1-a7f9-2de008ca6508)

* * *

## 🧾 Other Notable Changes

- [`presets` for DatePicker](https://mantine.dev/changelog/8-1-0/#datepicker-presets): Add predefined date ranges
- [Popover improvements](https://mantine.dev/changelog/8-1-0/#popover-middlewares-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](https://mantine.dev/changelog/8-1-0/#other-changes) for more.

* * *

## ⚡ 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:

```python
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)

```

* * *

### 🙌 Thank You

Huge thanks to @ihor-lazariev for the AutoComplete improvements in [PR #604](https://github.com/snehilvj/dash-mantine-components/pull/604).

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

---

<div class="post-metadata">

**Author:** ![PipInstallPython](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/pipinstallpython/32/34539_2.png) [@PipInstallPython](https://community.plotly.com/u/PipInstallPython)\
**Post date:** [July 1, 2025, 3:17pm UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/2 "2025-07-01T15:17:20Z")

</div>

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

 ![Screenshot 2025-07-01 at 10.33.38 AM](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/1/6/163c8caa750c1658aeaee3f9a4e9cf6cf001e5c3.jpeg)

🤩 that dmc.🎄 tho!

---

<div class="post-metadata">

**Author:** ![adamschroeder](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/adamschroeder/32/17280_2.png) [@adamschroeder](https://community.plotly.com/u/adamschroeder)\
**Post date:** [July 1, 2025, 3:22pm UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/3 "2025-07-01T15:22:28Z")

</div>

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 🙏

---

<div class="post-metadata">

**Author:** ![adamschroeder](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/adamschroeder/32/17280_2.png) [@adamschroeder](https://community.plotly.com/u/adamschroeder)\
**Post date:** [July 1, 2025, 3:22pm UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/4 "2025-07-01T15:22:41Z")

</div>

Pinned globally on July 1, 2025, 3:22pm UTC



---

<div class="post-metadata">

**Author:** ![PipInstallPython](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/pipinstallpython/32/34539_2.png) [@PipInstallPython](https://community.plotly.com/u/PipInstallPython)\
**Post date:** [July 2, 2025, 2:55am UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/5 "2025-07-02T02:55:18Z")

</div>

![Screenshot 2025-07-01 at 9.51.57 PM](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/e/0/e0f9cfe2c0bbf6ff672bb32a37d750c72e18af5c.jpeg)  
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

```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:

```py
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"}
                ),

```

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [July 2, 2025, 3:41am UTC](https://community.plotly.com/t/dash-mantine-components-2-1-0-release/92942/6 "2025-07-02T03:41:55Z")

</div>

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.:

> **[Dash Mantine Components | JavaScript Functions as Props](https://www.dash-mantine-components.com/functions-as-props)**
>
> Introduction to using JavaScript functions with Dash Mantine Components
