Stop NavLink from changing URL?

Hi everyone!

Below is an example of a webapp I have.
It is working as intended. I click on internal links on the left sidebar and right hand side is getting scrolled where it should.

The only thing that is bothering me is that when a link is clicked it is also affecting the URL of the whole app.

Example: original URL is home.com. After I click a link on the sidebar, URL becomes home.com/#link3

How do I stop URL from changing each time I click on link from sidebar?

Thanks for any help in advance!

from email import header
import dash
from dash import Dash, html, dcc
import dash_bootstrap_components as dbc

app=Dash(__name__, external_stylesheets=[dbc.themes.SUPERHERO])
server = app.server

SIDEBAR_STYLE = {
    "position": "fixed",
    "top": 100,
    "left": 0,
    "bottom": 0,
    "width": "16rem",
    "padding": "2rem 1rem",
}

sidebar = html.Div(
    [
        # html.H2("Contents", className="display-4"),
        # html.Hr(),
        dbc.Nav(
            [
                dbc.NavLink("Link1", href="#link1", external_link=True),
                dbc.NavLink("Link2", href="#link2", external_link=True),
                dbc.NavLink("Link3", href="#link3", external_link=True),
                dbc.NavLink("Link4", href="#link4", external_link=True),
                dbc.NavLink("Link5", href="#link5", external_link=True),
                dbc.NavLink("Link6", href="#link6", external_link=True),
                dbc.NavLink("Link7", href="#link7", external_link=True),
            ],
            vertical=True,
            pills=True,
        ),
    ],
    style=SIDEBAR_STYLE,
)

layout=html.Div(
            html.Div([
                # dcc.Markdown("# Curriculum Vitae",style={"textAlign":"center"}),
                html.Br(id="link1"),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link1""",
                    # id="link1",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link2"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link2""",
                    # id="link2",
                    style={"textAlign":"left"}
                ),
                html.Br(id="link3"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link3""",
                    # id="link2",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link4"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link4""",
                    # id="link4",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                
                html.Br(id="link5"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link5""",
                    # id="link3",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(),
                html.Br(id="link6"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link6""",
                    # id="link6",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link7"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link7""",
                    # id="link6",
                    style={"textAlign":"left"}
                ),
            ]),
            id="page-content",
            # style=CONTENT_STYLE
)

app.layout = html.Div([
    dbc.Row([
    dbc.Col(sidebar),
    dbc.Col(layout)])])

if __name__=="__main__":
    app.run_server(debug=False)

Hi @mrel ,

I think you can update address bar without hashtag # by using history.pushState() from HTML5 history API and you need client side callback to call this function.

First, adding your dbc.NavLink components with id .

... 
                dbc.NavLink("Link1", href="#link1", external_link=True,id="navlink1"),
                dbc.NavLink("Link2", href="#link2", external_link=True,id="navlink2"),
                dbc.NavLink("Link3", href="#link3", external_link=True,id="navlink3"),
                dbc.NavLink("Link4", href="#link4", external_link=True,id="navlink4"),
                dbc.NavLink("Link5", href="#link5", external_link=True,id="navlink5"),
                dbc.NavLink("Link6", href="#link6", external_link=True,id="navlink6"),
                dbc.NavLink("Link7", href="#link7", external_link=True,id="navlink7"),
....

Create client side callback of every NavLink components, to modify address bar when link is clicked.

for i in range(1,8):
    input_component = "navlink"+str(i)
    output_component = "link"+str(i)
    app.clientside_callback(
        """
        function(n_clicks) {
            if (n_clicks > 0) {
                window.history.pushState("", "Dash", "/");
            }
        }
        """,
        dash.Output(output_component, "children"),
        [dash.Input(input_component, "n_clicks")]
    )

Finally wrap up and merge with your code.

from email import header
import dash
from dash import Dash, html, dcc
import dash_bootstrap_components as dbc

app=Dash(__name__, external_stylesheets=[dbc.themes.SUPERHERO])
server = app.server

SIDEBAR_STYLE = {
    "position": "fixed",
    "top": 100,
    "left": 0,
    "bottom": 0,
    "width": "16rem",
    "padding": "2rem 1rem",
}

sidebar = html.Div(
    [
        # html.H2("Contents", className="display-4"),
        # html.Hr(),
        dbc.Nav(
            [
                dbc.NavLink("Link1", href="#link1", external_link=True,id="navlink1"),
                dbc.NavLink("Link2", href="#link2", external_link=True,id="navlink2"),
                dbc.NavLink("Link3", href="#link3", external_link=True,id="navlink3"),
                dbc.NavLink("Link4", href="#link4", external_link=False,id="navlink4"),
                dbc.NavLink("Link5", href="#link5", external_link=True,id="navlink5"),
                dbc.NavLink("Link6", href="#link6", external_link=True,id="navlink6"),
                dbc.NavLink("Link7", href="#link7", external_link=True,id="navlink7"),
            ],
            vertical=True,
            pills=True,
        ),
    ],
    style=SIDEBAR_STYLE,
)

layout=html.Div(
            html.Div([
                # dcc.Markdown("# Curriculum Vitae",style={"textAlign":"center"}),
                html.Br(id="link1"),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link1""",
                    # id="link1",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link2"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link2""",
                    # id="link2",
                    style={"textAlign":"left"}
                ),
                html.Br(id="link3"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link3""",
                    # id="link2",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link4"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link4""",
                    # id="link4",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                
                html.Br(id="link5"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link5""",
                    # id="link3",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(),
                html.Br(id="link6"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link6""",
                    # id="link6",
                    style={"textAlign":"left"}
                ),
                html.Hr(),
                html.Br(id="link7"),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Br(),
                html.Hr(),
                dcc.Markdown(
                    """## Link7""",
                    # id="link6",
                    style={"textAlign":"left"}
                ),
            ]),
            id="page-content",
            # style=CONTENT_STYLE
)

app.layout = html.Div([
    dbc.Row([
    dbc.Col(sidebar),
    dbc.Col(layout)])])

for i in range(1,8):
    input_component = "navlink"+str(i)
    output_component = "link"+str(i)
    app.clientside_callback(
        """
        function(n_clicks) {
            if (n_clicks > 0) {
                window.history.pushState("", "Dash", "/");
            }
        }
        """,
        dash.Output(output_component, "children"),
        [dash.Input(input_component, "n_clicks")]
    )
    

if __name__=="__main__":
    app.run_server(debug=False)

Hope this help.

2 Likes

Thank you, @farispriadi ! Perfectly working!