Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,39 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased]

### Added
- [#3947](https://github.com/plotly/dash/pull/3947) Make `plotly-cloud` a default install dependency of Dash instead of an optional extra, so the `plotly` CLI and Dash's cloud integration are available out of the box. The `dash[cloud]` extra is kept for backward compatibility.
- [#3930](https://github.com/plotly/dash/pull/3930) Shared storage: a backend-agnostic state manager available on every app via `dash.ctx.shared_storage` (and `app.shared_storage`), for sharing state between callbacks or across worker processes without an external service. Started lazily on first use, so it costs nothing until touched; pass `shared_storage=None` to `Dash(...)` to disable.
- Cross-process key/value store (`get`/`set`/`delete`, with optional TTL) and ordered, replayable publish/subscribe (`publish`/`subscribe`). Subscriptions resume from the caller's last-seen sequence out of a bounded buffer, and a buffer overrun surfaces as an explicit gap rather than a silent loss. Values must be JSON-compatible (like `dcc.Store`).
- Three backends ship, selected by passing a `BaseSharedStorage` instance to `shared_storage=`:
- `LocalSharedStorage` (default): in-memory, elects one owner process per machine over an `AF_UNIX`/loopback socket, correct within a single container, including across multiple gunicorn workers.
- `DiskcacheSharedStorage`: on a `diskcache.Cache`, shared by every process on one host, for single-machine deployments (not for multi-pod ones with ephemeral disks).
- `RedisSharedStorage`: on Redis, using Redis Streams for the ordered pub/sub: the backend for horizontally-scaled deployments behind a load balancer, e.g. apps scaled across pods.
- `LocalSharedStorage` additionally accepts `mode=` to make its key/value store durable: `"memory"` (default, in-memory only), `"persist"` (write-through to disk on every change), or `"persist-reset"` (in-memory speed with a periodic flush every `flush_interval` seconds and on clean exit). Persistent modes recover on start and on owner re-election, so state survives a process restart or a crashed owner. Data is stored in a chunked, atomically-written msgpack store (a per-namespace folder under the user cache directory by default, overridable via `path=`). TTLs are preserved across restarts; pub/sub remains transient.
- [#3931](https://github.com/plotly/dash/pull/3931) Streaming callbacks: a callback defined as an `async def` generator streams its yields to the browser as they are produced (`dash.Patch` yields give incremental updates). All of a browser's streams share one connection hosted in a SharedWorker, so they don't count against the per-host connection limit; closing a tab cancels its streams.
- [#3947](https://github.com/plotly/dash/pull/3947) Make `plotly-cloud` a default install dependency of Dash instead of an optional extra, so the `plotly` CLI and Dash's cloud integration work out of the box. The `dash[cloud]` extra is kept for backward compatibility.
- [#3930](https://github.com/plotly/dash/pull/3930) Add shared storage: a backend-agnostic cross-process state manager (key/value with optional TTL, plus ordered replayable pub/sub) on every app via `dash.ctx.shared_storage`, started lazily and disabled with `shared_storage=None`. Ships `LocalSharedStorage` (default, in-memory with optional disk persistence), `DiskcacheSharedStorage`, and `RedisSharedStorage` for horizontally-scaled deployments; see `.ai/ARCHITECTURE.md`.
- [#3931](https://github.com/plotly/dash/pull/3931) Add streaming callbacks: an `async def` generator callback streams its yields to the browser as they are produced (`dash.Patch` yields apply incrementally). A browser's streams share one SharedWorker-hosted connection so they do not count against the per-host connection limit; closing a tab cancels its streams.
- [#3977](https://github.com/plotly/dash/pull/3977) Add partial WebSocket prop reads with `get_prop(..., path=...)`. Closes [#3975](https://github.com/plotly/dash/issues/3975).
- [#3765](https://github.com/plotly/dash/pull/3765) Add opt-in partial pattern matching for callback `Input`, `Output`, and `State` dependencies via `partial_pattern=True`. Dictionary ID patterns can now match component IDs containing additional keys, and partial patterns can be combined with `ALL` and `MATCH` wildcards. Fixes [#3764](https://github.com/plotly/dash/issues/3764).
- [#3646](https://github.com/plotly/dash/pull/3646) Experimental support for React 19. The default is still React 18.3.1; to use React 19 set the environment variable `REACT_VERSION=19.2.4` before running your app, or call `dash._dash_renderer._set_react_version("19.2.4")` inside the app. React 19 has no official UMD builds, so Dash serves the [`umd-react`](https://www.npmjs.com/package/umd-react) package, together with a compatibility shim loaded after react-dom and before any component package. The shim keeps component libraries built against React <=18 (e.g. dash-bootstrap-components, dash-mantine-components) working under React 19: it stubs the removed `ReactCurrentOwner` internals, redirects the legacy element `$$typeof` symbol so pre-bundled React 18 jsx-runtimes produce elements React 19 accepts (error #525), and exposes a global `react/jsx-runtime` (`window.ReactJSXRuntime`) that Dash's own component bundles externalize to. Component library authors adopting this convention should copy the defensive `jsxRuntimeExternal` webpack external from `components/dash-core-components/webpack.config.js` rather than a bare `'ReactJSXRuntime'` string: it falls back to a `React.createElement`-based runtime when the global is missing, so the same build also works on Dash versions older than this release.
- [#3925](https://github.com/plotly/dash/pull/3925) Add optional callback request payload compression for server-side callbacks via `compress_payload` and `compress_threshold` callback parameters (default threshold: 5,000 bytes). When enabled and the request body exceeds the threshold, the renderer sends gzip-compressed binary payloads with `Content-Encoding: gzip`, and Dash transparently decompresses on the server (Flask, FastAPI, and Quart). This can significantly reduce callback roundtrip times for large client-to-server payloads. Fixes [#3924](https://github.com/plotly/dash/issues/3924).
- [#3765](https://github.com/plotly/dash/pull/3765) Add opt-in partial pattern matching for callback `Input`, `Output`, and `State` via `partial_pattern=True`, so dictionary ID patterns can match component IDs with extra keys and combine with `ALL`/`MATCH` wildcards. Fixes [#3764](https://github.com/plotly/dash/issues/3764).
- [#3646](https://github.com/plotly/dash/pull/3646) Add experimental support for React 19 (default stays React 18.3.1); opt in with `REACT_VERSION=19.2.4` or `dash._dash_renderer._set_react_version("19.2.4")`. Dash serves the [`umd-react`](https://www.npmjs.com/package/umd-react) package with a compatibility shim so component libraries built against React <=18 keep working; see `.ai/ARCHITECTURE.md`.
- [#3925](https://github.com/plotly/dash/pull/3925) Add optional callback request payload compression via `compress_payload` and `compress_threshold` callback parameters (default threshold 5,000 bytes), sending gzip payloads that Dash decompresses on Flask, FastAPI, and Quart. Fixes [#3924](https://github.com/plotly/dash/issues/3924).
- [#3961](https://github.com/plotly/dash/pull/3961) Added cursor position data (`xPixel`, `yPixel`) to `dcc.Graph` `hoverData` and `clickData` when `hoveranywhere` or `clickanywhere` is enabled in the figure.
- [#3960](https://github.com/plotly/dash/pull/3960) Rewrite `dcc.Markdown` and `dcc.Link` as Typescript components
- Added `dash.remount`, a wrapper for a component returned from a callback that forces the renderer to remount it - unmounting the existing instance and mounting a fresh one, resetting its internal state - instead of reconciling it in place. This is the explicit, opt-in way to reset a stateful component (eg. AG Grid, a dropdown keeping transient UI state) from a callback without having to change its `id`.
- Added `dash.remount`, a wrapper for a callback-returned component that forces the renderer to remount it (resetting its internal state) instead of reconciling in place: the explicit way to reset a stateful component from a callback without changing its `id`.

### Removed
- [#3646](https://github.com/plotly/dash/pull/3646) Remove React 16 support (`16.14.0` is no longer an accepted value for `REACT_VERSION` / `_set_react_version`).

### Changed
- [#3986](https://github.com/plotly/dash/pull/3986) Adjust `_run_before_hooks` in the `fastapi` backend to honor a response returned by a `before_request` function, matching the `flask` backend's behavior.

### Fixed
- [#3944](https://github.com/plotly/dash/pull/3944) Fix `dash.testing` runner backend detection for wrapped FastAPI/Quart servers so threaded Flask-only options are not passed to ASGI runners.
- [#3955](https://github.com/plotly/dash/pull/3955) Unpin `selenium` in the testing requirements (was capped at `<=4.2.0`, from 2022) and require `>=4.11.0`. The old cap predated Selenium Manager, so the pinned selenium could not drive the current stable Chrome (151+) that CI installs, producing widespread `StaleElementReferenceException`/`TimeoutException` flakiness across the browser-based integration tests. Modern selenium auto-provisions a matching chromedriver, restoring stable CI runs.
- Speed up the layout crawl the renderer runs on every path recompute and callback gather (`crawlLayout` and its callers) by replacing curried-ramda `path`/`pathOr` lookups with direct property access on the per-node hot path. Cut a `Patch().append()` into a large container by ~16% and initial render / wildcard resolution by a few percent, with no behavior change.
- Fix pattern-matching (`MATCH`/`ALL`/`ALLSMALLER`) callbacks getting quadratically slower as the number of matching components grows. Resolving a wildcard dispatch looked up each component's path with a linear deep-equality scan over every component sharing the id's key set, so resolving an `ALL` callback over N components was O(N²). The renderer now keeps an O(1) id→path index alongside the ordered table, cutting an `ALL` update over 400 components from ~580ms to ~140ms (~4x). No app changes required.
- [#3941](https://github.com/plotly/dash/pull/3941) Fix the FastAPI and Quart backends opening a WebSocket connection on every page load, even for apps with no WebSocket callbacks. The renderer keyed the connection on the mere presence of WebSocket infrastructure (always advertised by these backends) rather than on whether it was needed. The socket now opens eagerly only when `websocket_callbacks=True`; with just per-callback `websocket=True` it opens lazily on the first such callback dispatch, and an app with no WebSocket callbacks never opens one. Fixes [#3939](https://github.com/plotly/dash/issues/3939).
- [#3955](https://github.com/plotly/dash/pull/3955) Unpin `selenium` in the testing requirements (was capped at `<=4.2.0` from 2022) and require `>=4.11.0`, so it can drive current stable Chrome via Selenium Manager and stop the widespread CI flakiness.
- Speed up the renderer layout crawl (`crawlLayout` and its callers) by replacing curried-ramda `path`/`pathOr` lookups with direct property access on the hot path: ~16% faster `Patch().append()` into a large container, with no behavior change.
- Fix pattern-matching (`MATCH`/`ALL`/`ALLSMALLER`) callbacks getting quadratically slower as matching components grow; a new O(1) id->path index cuts an `ALL` update over 400 components from ~580ms to ~140ms (~4x), with no app changes.
- [#3941](https://github.com/plotly/dash/pull/3941) Fix the FastAPI and Quart backends opening a WebSocket connection on every page load even for apps with no WebSocket callbacks; the socket now opens only when actually needed. Fixes [#3939](https://github.com/plotly/dash/issues/3939).
- [#3916](https://github.com/plotly/dash/pull/3916) Fixed a regression where dragging multiple files into `dcc.Upload` would upload only the first file when `multiple=True`
- [#3922](https://github.com/plotly/dash/pull/3922) Fix `dcc.Input(type="number")` stepper behavior when only `min` is set.
- [#3925](https://github.com/plotly/dash/pull/3925) Use the proxied url as the Jupyter server url so `DASH_PROXY` is honored by the external url and inline iframe in notebooks.
- [#3938](https://github.com/plotly/dash/pull/3938) Fix `dcc.Patch()` re-running the initial callbacks of components that were already on the page, including every matching (`MATCH`/`ALL`) element, and wiping their user-edited persisted values. Fixes [#3681](https://github.com/plotly/dash/issues/3681) and [#3937](https://github.com/plotly/dash/issues/3937)
- [#3938](https://github.com/plotly/dash/pull/3938) Fix `dcc.Patch()` re-running the initial callbacks of components already on the page (including every `MATCH`/`ALL` element) and wiping their user-edited persisted values. Fixes [#3681](https://github.com/plotly/dash/issues/3681) and [#3937](https://github.com/plotly/dash/issues/3937)
- [#3960](https://github.com/plotly/dash/pull/3960) Fix `dcc.Markdown` not rendering `<dccLink />` by using newer dependencies
- [#3846](https://github.com/plotly/dash/issues/3846) Fix children returned by a callback being unmounted and remounted on every update instead of reconciled in place, which reset component state and slowed rendering of large subtrees 3-4x (regression introduced in 4.2.0 by [#3570](https://github.com/plotly/dash/pull/3570)). A component passed from a parent is now only remounted when its identity (namespace, type or id) at that position actually changed; the same component with new prop values updates in place, restoring pre-4.2 behavior. To force a remount of a stateful component from a callback, wrap it with `dash.remount` (or return it with a different `id`).
- Fix components rendered as props (eg. component labels in `dcc.Dropdown` options, `dcc.Tab` labels) crashing with "can't access property 'props', layout is undefined" or failing to update when the host component's subtree was replaced by a callback. Components inserted out of the layout tree via `ExternalWrapper` now re-insert themselves when their layout entry was removed, so they update in place instead of updating a stale path.
- [#3929](https://github.com/plotly/dash/issues/3929) Fix components that set their own initial state on mount (eg. `dash-bootstrap-components` `Tabs`, which selects its default active tab) not applying that state on first render - a component's descendant layout hashes were reset on its very first fresh render, discarding the mount-time update before it took effect. The reset now only runs from the second fresh render onward, so a component's initial state survives (regression introduced in 4.2.0 by [#3570](https://github.com/plotly/dash/pull/3570)).
- [#3846](https://github.com/plotly/dash/issues/3846) Fix callback-returned children being unmounted and remounted on every update instead of reconciled in place, which reset component state and slowed large subtrees 3-4x (regression introduced in 4.2.0 by [#3570](https://github.com/plotly/dash/pull/3570)); use `dash.remount` to force a remount.
- Fix components rendered as props (eg. `dcc.Dropdown` option labels, `dcc.Tab` labels) crashing or failing to update when the host subtree was replaced by a callback; out-of-tree `ExternalWrapper` components now re-insert themselves and update in place.
- [#3929](https://github.com/plotly/dash/issues/3929) Fix components that set their own initial state on mount (eg. `dash-bootstrap-components` `Tabs`) not applying it on first render, because descendant layout hashes were reset on the first fresh render (regression introduced in 4.2.0 by [#3570](https://github.com/plotly/dash/pull/3570)).
- [#3948](https://github.com/plotly/dash/issues/3948) Fix page getting progressively slower as callbacks append children

### Changed
- [#3986](https://github.com/plotly/dash/pull/3986) Adjusted the `_run_before_hooks` inf `fastapi` backend to allow for a return value in the event that a `before_request` function returns a response. This is more aligned with how the `before_request` hooks work in the `flask` backend.

## [4.4.1] - 2026-07-21

## Fixed
Expand Down
Loading