From 33d9adbef1632c0ef7100b40129f4d12ec6d6f3c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 19 Aug 2026 12:57:58 -0500 Subject: [PATCH] [web_server] Only add the offline hint without captive_portal --- esphome/components/web_server/__init__.py | 14 +++++++++++--- tests/unit_tests/components/test_web_server.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index d9f357f8f4..3e9fa45b28 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -333,7 +333,7 @@ async def add_entity_config(entity, config): ) -def build_index_html(config) -> str: +def build_index_html(config: ConfigType, offline_hint: bool = True) -> str: html = "" css_include = config.get(CONF_CSS_INCLUDE) js_include = config.get(CONF_JS_INCLUDE) @@ -345,7 +345,8 @@ def build_index_html(config) -> str: if js_include: html += "" html += "" - if js_url := config[CONF_JS_URL]: + js_url = config[CONF_JS_URL] + if js_url and offline_hint: # The interface is downloaded from the internet. Show a hint instead of a blank # page when the browser cannot reach it, which is common in WiFi AP mode. hint = ( @@ -359,6 +360,8 @@ def build_index_html(config) -> str: hint.replace("\\", "\\\\").replace("'", "\\'"), quote=True ) html += f'' + elif js_url: + html += f'' html += "" return html @@ -396,7 +399,12 @@ async def to_code(config): cg.add_define("USE_WEBSERVER_VERSION", version) if version >= 2: # Don't compress the index HTML as the data sizes are almost the same. - add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False) + # With captive_portal the AP serves its own local page, so the offline hint is + # only useful without it. + index_html = build_index_html( + config, offline_hint="captive_portal" not in CORE.config + ) + add_resource_as_progmem("INDEX_HTML", index_html, compress=False) else: cg.add(var.set_css_url(config[CONF_CSS_URL])) cg.add(var.set_js_url(config[CONF_JS_URL])) diff --git a/tests/unit_tests/components/test_web_server.py b/tests/unit_tests/components/test_web_server.py index 6245f9a6f9..021a734109 100644 --- a/tests/unit_tests/components/test_web_server.py +++ b/tests/unit_tests/components/test_web_server.py @@ -21,6 +21,16 @@ def test_build_index_html_escapes_hint() -> None: assert "a\\'b"c.js" in html +def test_build_index_html_hint_disabled() -> None: + """The plain script tag is kept when the hint is not wanted (captive_portal).""" + html = build_index_html( + {CONF_JS_URL: "https://oi.esphome.io/v2/www.js", CONF_CSS_URL: ""}, + offline_hint=False, + ) + assert '' in html + assert "onerror" not in html + + def test_build_index_html_without_js_url() -> None: """No hosted script and no hint when js_url is empty.""" html = build_index_html({CONF_JS_URL: "", CONF_CSS_URL: ""})