How to trigger html.Button in dcc.Markdown

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