hi all, this is the third web app i’m building using dash. I want to design a left side-bar with two dropdowns with minimal spacing between the top and bottom dropdowns. i succesfully did that but i want to design it in way that when the top dropdown is opened, the the one at the bottom is not covered but moves directly below it. After the top dropdown option is selected, the dropdown below it moves back to its original position. Is it possible to do that using clientside-callbacks or is there another way?
Not sure if this is exactly what you are referring to but I used dmc.Drawer and dmc.Accordion to get my navigation looking pretty:
dmc.Drawer(
title="Drawer Example",
id="drawer-simple",
padding="md",
zIndex=1000,
children=[
dmc.Box(
children=[
dmc.Image(
radius="md",
src="assets/world_animated.gif",
fit="contain",
style={
"width": "60%",
"height": "60%",
"objectFit": "contain",
"position": "absolute",
"top": "50%",
"left": "50%",
"transform": "translate(-50%, -50%)"
}
),
dmc.Image(
radius="md",
src="assets/coatofarms.png",
fit="contain",
style={
"position": "absolute",
"top": 0,
"left": 0,
"width": "100%",
"height": "100%",
"objectFit": "contain",
"zIndex": 1
}
)
],
style={
"position": "relative",
"width": "100%",
"height": "150px", # Adjust this value as needed
"overflow": "hidden" # This ensures the transformed image doesn't overflow
}
),
dmc.Divider(label="Navigation", color='orange'),
dmc.Stack([
dmc.Group([
dmc.Accordion(
value=["flexibility"],
multiple=True,
children=[
dmc.AccordionItem(
[
dmc.AccordionControl("Cartography", style={"fontSize": 24}, icon=DashIconify(icon="noto:world-map", width=30),),
dmc.AccordionPanel(
dmc.Stack([
dmc.Group([
dmc.Space(w=20),
DashIconify(icon="noto:globe-showing-americas", width=30),
dmc.Anchor(
"Aransas Map",
href="/",
style={'color': 'white', "fontSize": 24}
)
]),
])
),
],
value="cartography",
),
dmc.AccordionItem(
[
dmc.AccordionControl("Freeform", style={"fontSize": 24}, icon=DashIconify(icon="vscode-icons:file-type-libreoffice-draw", width=30),),
dmc.AccordionPanel(
dmc.Stack([
dmc.Group([
dmc.Space(w=20),
DashIconify(icon="noto-v1:man-artist-light-skin-tone", width=30),
dmc.Anchor(
"Create Notes",
href="/freeform",
style={'color': 'white', "fontSize": 24}
)
]),
dmc.Group([
dmc.Space(w=20),
dmc.Tooltip(
label="🏗️ Under Construction 🚧",
position="right",
offset=10,
children=[
DashIconify(icon="logos:teamgrid", width=30),
],
zIndex=1005,
withArrow=True,
transitionProps={
"transition": "scale-y",
"duration": 200,
"timingFunction": "ease",
},
),
dmc.Skeleton(h=24, w=150,),
# dmc.Anchor(
# "Publications",
# href="/freeform/publications",
# style={'color': 'white', "fontSize": 24}
# )
]),
]),
),
],
value="freeform",
),
dmc.AccordionItem(
[
dmc.AccordionControl("360 Panorama", style={"fontSize": 24}, icon=DashIconify(icon="flat-color-icons:panorama", width=30),),
dmc.AccordionPanel(
dmc.Stack([
dmc.Group([
dmc.Space(w=20),
DashIconify(icon="fxemoji:videogame", width=30),
dmc.Anchor(
"Geo Guesser Game",
href="/geo_game_select",
style={'color': 'white', "fontSize": 24}
)], style={ }),
]),
),
],
value="panorama",
),
],
)
], grow=True),
# dmc.Group([
#
# dmc.Image(
# radius="md",
# h=30,
# w=30,
# src="assets/sensor.png",
# ),
# dmc.Anchor(
# "Sensor Management",
# href="https://community.plotly.com/t/dash-mantine-components/58414",
# style={'color': 'white', "fontSize": 24},
# )]),
dmc.Divider(label="Sister Applications", color='orange'),
dmc.Group([
DashIconify(icon="skill-icons:django", width=30),
dmc.Anchor(
"Django",
href="https://geomapindex.com/",
style={'color': 'white', "fontSize": 24},
)]),
dmc.Group([
DashIconify(icon="logos:amazon-connect", width=30),
dmc.Anchor(
"API",
href="https://geomapindex.com/api/docs",
style={'color': 'white', "fontSize": 24},
)]),
dmc.Group([
DashIconify(icon="flat-color-icons:shop", width=30),
dmc.Anchor(
"Shop",
href="https://pipinstallpython.pythonanywhere.com/catalogue/",
style={'color': 'white', "fontSize": 24,
},
)], ),
dmc.Divider(label="Resources", color='orange'),
dmc.Group([
DashIconify(icon="vscode-icons:folder-type-docs-opened", width=30),
dmc.Anchor(
"Docs",
href="https://pip-install-python.com/",
style={'color': 'white', "fontSize": 24},
)]),
dmc.Group([
DashIconify(icon="openmoji:youtube", width=30),
dmc.Anchor(
"Youtube",
href="https://www.youtube.com/@pipinstallpython",
style={'color': 'white', "fontSize": 24},
)]),
dmc.Group([
DashIconify(icon="openmoji:github", width=30),
dmc.Anchor(
"Github",
href="https://github.com/pip-install-python",
style={'color': 'white', "fontSize": 24},
)]),
], align='stretch', justify='flex-start')
]
),
Still need to route a callback and a button to open and close the dmc.Drawer
Below are two approaches for achieving this functionality.
Approach 1: Custom JavaScript Event Listeners
In this approach, we directly manipulate the style of the dropdown based on focus and blur events using custom JavaScript. This method is straightforward and gives you precise control over the dropdown behavior.
from dash import Dash, dcc, html, Input, Output, _dash_renderer
import dash_mantine_components as dmc
from dash_iconify import DashIconify
_dash_renderer._set_react_version('18.2.0')
app = Dash(__name__)
# Define layout
app.layout = dmc.MantineProvider(
children=[
dmc.Box(
children=[
dmc.Select(
label="Your favorite library",
data=["Pandas", "NumPy", "TensorFlow", "PyTorch", "Python", "Java", "G0", "Dash", "Plolty"],
value='Pandas',
placeholder="Pick values",
id='select',
w=400,
maxDropdownHeight = 200,
),
dmc.Select(
label="Your favorite library",
data=["Pandas", "NumPy", "TensorFlow", "PyTorch"],
value='Pandas',
placeholder="Pick values",
id='select-2',
w=400,
),
]
)
]
)
# Custom JavaScript to detect focus and open state
app.clientside_callback(
"""
function(value) {
const no_update = window.dash_clientside.no_update
var selectInput = document.querySelector("#select");
if (selectInput) {
selectInput.addEventListener("focus", () => {
console.log("Dropdown focused");
document.getElementById("select").style.marginBottom = "220px";
});
selectInput.addEventListener("blur", () => {
console.log("Dropdown unfocused");
document.getElementById("select").style.marginBottom = "0px";
});
}
return no_update;
}
""",
Output("select", "children"),
Input("select", "value")
)
# Run app
if __name__ == "__main__":
app.run_server(debug=True)
Approach 2: Using dropdownOpened
Property
Alternatively, the Dash Mantine Components library provides a dropdownOpened
property that can be used to detect whether the dropdown is open. However, I’ve encountered a bug in the library that prevents this property from functioning correctly. As a result, this approach may not work as expected at the moment.
@AnnMarieW is this how the property (dropdownOpened
) should be used?
from dash import Dash, dcc, html, Input, Output, _dash_renderer
import dash_mantine_components as dmc
from dash_iconify import DashIconify
# Set React version
_dash_renderer._set_react_version('18.2.0')
app = Dash(__name__)
# Define layout
app.layout = dmc.MantineProvider(
children=[
dmc.Box(
children=[
dmc.Select(
label="Your favorite library",
data=["Pandas", "NumPy", "TensorFlow", "PyTorch"],
value='Pandas',
placeholder="Pick values",
id='select',
w=400,
),
dmc.Select(
label="Another Select",
data=["Pandas", "NumPy", "TensorFlow", "PyTorch"],
value='Pandas',
placeholder="Pick values",
id='select-2',
w=400,
),
]
)
]
)
# Attempt to use dropdownOpened property (currently not functional due to a bug)
app.clientside_callback(
"""
function(isDropdownOpen, value) {
console.log("Dropdown Open:", isDropdownOpen); // Log dropdown focus state
return isDropdownOpen ? [{"marginBottom": "300px"}] : [{"marginBottom": "0px"}];
}
""",
Output("select", "style"),
Input("select", "dropdownOpened"),
Input("select", "value"),
)
if __name__ == "__main__":
app.run_server(debug=True)
Hi @Amazigh
The dropdownOpened
can be used to manually open or close the dropdown in a callback, but it currently is not updated based on user interaction.
@Flexxie
It is not typical for a dropdown to move other content on the page. While it’s possible to make that happen it adds additional complexity to the app.
For that type it functionality, it would be better to use something like a dmc.Accordion
as @PipInstallPython suggested.
Hi @Flexxie ,
What about NavLink component in dash mantine components https://www.dash-mantine-components.com/components/navlink? If you pass children to it it will have the exact functionality as you described. I use it in navbars:
collapsed:
uncollapsed: