Is there a way to put an html.Button in dcc.Markdown that can trigger a callback when it is clicked?
You can’t exactly put an ‘html.Button()’ exactly inside markdown, but you can get pretty close. You can make the markdown itself clickable surrounding it with a html.Div() and triggering a callback the div’s n_clicks property.
from dash import Dash, html, Input, Output, callback, dcc
app = Dash()
app.layout = html.Div(
[
html.Div(
[dcc.Markdown(r"$\frac{clickable}{markdown}*\pi$", mathjax=True)],
id="click-div",
style={"color": "red", "font-weight": "bold"},
),
html.P(id="click-output"),
]
)
@callback(
Output("click-output", "children"),
Input("click-div", "n_clicks")
)
def click_counter(n_clicks):
return f"The markdown above has been clicked this many times: {n_clicks}"
app.run(debug=True)
You could do something like this:
import dash
from dash import dcc, html, Input, Output, State
app = dash.Dash(__name__)
app.layout = html.Div(
id="main_container",
style={
'maxWidth': '800px',
'margin': 'auto',
'padding': '20px',
'backgroundColor': '#f9f9f9',
'borderRadius': '12px',
'boxShadow': '0 8px 16px rgba(0,0,0,0.2)',
},
children=[
html.Div(
children=[
html.P(
"Button position relative to upper left corner of the rectangle",
style={'marginTop': '20px', 'textAlign': 'center'}
),
dcc.Input(id="top",value=50, debounce=True, type="number"),
dcc.Input(id="left",value=50, debounce=True, type="number"),
],
style={'textAlign': 'center'}
),
# --- Positioning Parent Container ---
# This Div contains both the Markdown and the Button.
# It MUST have 'position: relative' to serve as the reference point for the
# absolutely positioned child (the button).
html.Div(
id='positioning-container',
style={
'position': 'relative',
'height': '350px', # Give the container a fixed height to see the effect
'border': '3px solid red',
'padding': '20px',
'marginTop': '20px',
},
children=[
# 1. dcc.Markdown component (The main content/context of the parent area)
dcc.Markdown(
children=r"$\frac{20}{80}*\pi$",
mathjax=True,
style={
'color': '#4b5563',
'padding': '10px'
}
),
# 2. html.Button component (positioned absolutely)
html.Button(
'Floating Button',
id='btn',
style={
# IMPORTANT: Set position to 'absolute' to break it out of the normal flow
# and position it relative to the nearest 'position: relative' ancestor.
'position': 'absolute',
# Define the coordinates relative to the 'positioning-container'
'top': "50%",
'left': "50%",
"transform": "translate(-50%, -50%)", # Centers the button on the coordinates
'zIndex': '10', # Ensure it sits on top
'transition': 'all 0.2s', # control sliding animation
},
n_clicks=0,
)
]
),
html.Div(
id="out",
style={'marginTop': '20px', 'textAlign': 'center'}
)
]
)
@app.callback(
Output("out", "children"),
Input("btn", "n_clicks")
)
def show_clicks(clicks):
return f"button clicked {clicks} times."
@app.callback(
Output("btn", "style"),
Input("top", "value"),
Input("left", "value"),
State("btn", "style")
)
def show_clicks(top, left, style:dict):
style.update({"top": f"{top}%", "left": f"{left}%"})
return style
if __name__ == '__main__':
app.run(debug=True)
mred layout