Skip to content

Button: external_link leaks to the DOM as an attribute when the button renders in non-link mode (React non-boolean attribute warning) #1166

Description

@chilango74
  • dash version: 4.2.0
  • dash-bootstrap-components version: 2.0.4 (the relevant code is unchanged on current main)
  • components affected by bug: dbc.Button (verified; other components destructure external_link themselves)

What is happening?

When a dbc.Button carries external_link=True but renders in non-link mode, the external_link prop is spread onto the underlying DOM <button> element, and React logs a dev-console warning:

Non-link mode happens whenever useLink = href && !disabled is false, i.e.:

  1. href is not set — e.g. the layout declares the button and a callback fills href later (link-button whose URL is computed from form state), or
  2. href is set but the button is disabledhref={disabled ? undefined : href} strips the href, so a disabled link-button falls back to <button> and leaks too.

In src/components/button/Button.js external_link is not destructured in the function signature, so it travels inside ...otherProps and is spread onto <RBButton as='button' ...>. (In link mode it ends up consumed by the private Link component, which does destructure it — no leak there.)

React drops the attribute (it never appears in the DOM), so the impact is dev-console noise — but it fires on every page load for this common pattern, and external_link is a documented dbc prop being handed to the DOM rather than handled by the component.

What should be happening?

external_link should never reach the DOM element. In non-link mode it should simply be dropped (it only has meaning for links), the same way target is special-cased via linkTarget. E.g. destructure external_link in Button and forward it explicitly only when useLink:

function Button({ ..., external_link, ...otherProps }) {
  ...
  if (useLink) {
    otherProps['external_link'] = external_link;
    otherProps['linkTarget'] = target;
  }

Note external_link=True can't just be omitted by the app in this pattern: with a relative href and target="_blank", the private Link strips target and does same-tab SPA navigation unless external_link is true — so the prop has to be present in the layout even before href arrives.

Code

import dash
import dash_bootstrap_components as dbc

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = dbc.Button(
    "Open report in new tab",
    id="report-link",
    external_link=True,
    target="_blank",
    # href intentionally absent: a callback computes it from form state later.
    # Same warning if instead: href="/report", disabled=True
)

if __name__ == "__main__":
    app.run(debug=True)

Open the browser dev console on page load.

Error messages

Warning: Received `true` for a non-boolean attribute `external_link`.

If you want to write it to the DOM, pass a string instead: external_link="true" or external_link={value.toString()}.
    at button
    at https://.../dash_bootstrap_components.v2_0_4m1779801954.min.js:2:52987
    ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions