diff --git a/Cargo.lock b/Cargo.lock
index cfb28b36..2e3912ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -138,9 +138,9 @@ dependencies = [
"reqwest",
"serde",
"serde_core",
+ "serde_html_form 0.3.2",
"serde_json",
"serde_path_to_error",
- "serde_urlencoded",
"sha1",
"sync_wrapper",
"time",
@@ -206,7 +206,7 @@ dependencies = [
"rustversion",
"serde",
"serde_core",
- "serde_html_form",
+ "serde_html_form 0.2.7",
"serde_json",
"serde_path_to_error",
"tempfile",
@@ -1500,6 +1500,19 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_html_form"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acf96b1d9364968fce46ebb548f1c0e1d7eceae27bdff73865d42e6c7369d94"
+dependencies = [
+ "form_urlencoded",
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde_core",
+]
+
[[package]]
name = "serde_json"
version = "1.0.134"
diff --git a/axum-extra/Cargo.toml b/axum-extra/Cargo.toml
index 12040edb..9a3ef6cd 100644
--- a/axum-extra/Cargo.toml
+++ b/axum-extra/Cargo.toml
@@ -97,7 +97,7 @@ with-rejection = ["dep:axum"]
# Enabled by docs.rs because it uses all-features
# Enables upstream things linked to in docs
-__private_docs = ["axum/json", "dep:serde", "dep:tower"]
+__private_docs = ["axum/json", "axum/query", "dep:serde", "dep:tower"]
[dependencies]
axum-core = { path = "../axum-core", version = "0.5.5" }
@@ -124,6 +124,11 @@ percent-encoding = { version = "2.1", optional = true }
prost = { version = "0.14", optional = true }
rustversion = { version = "1.0.9", optional = true }
serde_core = { version = "1.0.221", optional = true }
+# DO NOT update. axum itself uses serde_html_form 0.3.x which has slightly
+# different behavior in some edge cases. This feature here is kept (deprecated)
+# to let people transition to that easier (fewer breaking changes to deal with
+# at once if they keep using axum_extra's `Query` / `Form` initially when going
+# to axum 0.9).
serde_html_form = { version = "0.2.0", optional = true }
serde_json = { version = "1.0.71", optional = true }
serde_path_to_error = { version = "0.1.8", optional = true }
diff --git a/axum-extra/src/extract/form.rs b/axum-extra/src/extract/form.rs
index 717d0a18..ce926489 100644
--- a/axum-extra/src/extract/form.rs
+++ b/axum-extra/src/extract/form.rs
@@ -1,3 +1,5 @@
+#![allow(deprecated)]
+
use axum::extract::rejection::RawFormRejection;
use axum::{
extract::{FromRequest, RawForm, Request},
@@ -12,31 +14,16 @@ use serde_core::de::DeserializeOwned;
///
/// `T` is expected to implement [`serde::Deserialize`].
///
-/// # Differences from `axum::extract::Form`
+/// # Deprecated
///
-/// This extractor uses [`serde_html_form`] under-the-hood which supports multi-value items. These
-/// are sent by multiple `` attributes of the same name (e.g. checkboxes) and `