diff --git a/CHANGELOG.md b/CHANGELOG.md index 41c8259c06..76c1600f8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## Unreleased + +### Added + +- [#2389](https://github.com/plotly/dash/pull/2389) Added `disable_n_clicks` prop to all html components to make it possible to remove onclick event listeners + ### Updated - [#2367](https://github.com/plotly/dash/pull/2367) Updated the default `favicon.ico` to the current Plotly logo diff --git a/components/dash-html-components/scripts/generate-components.js b/components/dash-html-components/scripts/generate-components.js index 13532f88b8..b548c385e4 100644 --- a/components/dash-html-components/scripts/generate-components.js +++ b/components/dash-html-components/scripts/generate-components.js @@ -138,6 +138,12 @@ function generatePropTypes(element, attributes) { */ 'n_clicks_timestamp': PropTypes.number, + /** + * When True, this will disable the n_clicks prop. Use this to remove + * event listeners that may interfere with screen readers. + */ + 'disable_n_clicks': PropTypes.bool, + /** * A unique identifier for the component, used to improve * performance by React.js while rendering components @@ -264,13 +270,17 @@ const ${Component} = (props) => { dataAttributes['data-dash-is-loading'] = true; } + /* remove unnecessary onClick event listeners */ + const isStatic = props.disable_n_clicks || !props.id; return ( <${element} - onClick={() => props.setProps({ + {...(!isStatic && {onClick: + () => props.setProps({ n_clicks: props.n_clicks + 1, n_clicks_timestamp: Date.now() + }) })} - {...omit(['n_clicks', 'n_clicks_timestamp', 'loading_state', 'setProps'], props)} + {...omit(['n_clicks', 'n_clicks_timestamp', 'loading_state', 'setProps', 'disable_n_clicks'], props)} {...dataAttributes} > {props.children} diff --git a/components/dash-html-components/tests/test_integration.py b/components/dash-html-components/tests/test_integration.py index 21cbbfd2ca..648c869df5 100644 --- a/components/dash-html-components/tests/test_integration.py +++ b/components/dash-html-components/tests/test_integration.py @@ -105,3 +105,35 @@ def update_output(*args): assert call_count.value == 3 assert not dash_duo.get_logs() + + def test_click_static(dash_duo): + app = Dash(__name__) + + app.layout = html.Div( + [ + html.Div("no event listener", className="div-1"), + html.Div("event listener", id="div-2", n_clicks=0), + html.Div("no event listener", id="div-3", n_clicks=0, disable_n_clicks=True), + html.Div("event listener", id="div-4", n_clicks=0, disable_n_clicks=False), + html.Div(id="div-output"), + ] + ) + + @app.callback( + Output("div-output", "children"), + Input("div-2", "n_clicks"), + Input("div-3", "n_clicks"), + Input("div-4", "n_clicks"), + prevent_initial_call=True, + ) + def update(n2, n3, n4): + return f"{n2}, {n3}, {n4}" + + dash_duo.start_server(app) + dash_duo.find_element("#div-2").click() + dash_duo.find_element("#div-3").click() + dash_duo.find_element("#div-4").click() + + dash_duo.wait_for_text_to_equal("#div-output", "1, 0, 1") + + assert not dash_duo.get_logs()