Forms and Multipart
Dioxus natively supports HTML Forms and Multipart uploads.
- HTML forms are collections of input elements represented as a list of key-value pairs
- Multipart requests are requests that contain multiple bodies
Many forms you'll build will be rather simple. Uploading them will only require a single request body. In some cases, as with file-uploads, you'll need a multi-part form data.
Forms
Dioxus Fullstack supports form uploads through Axum's typed  Form<T> type. Simply wrap a struct that implements  Serialize + Deserialize and pass it as an argument to a server function:
// Our form payload #[derive(Deserialize, Serialize)] pub struct LoginForm { username: String, password: String, } // Our form endpoint #[post("/api/login")] async fn login(form: Form<LoginForm>) -> Result<()> { // Verify the username and password. // In a real application, you'd check these against a database. if form.0.username == "admin" && form.0.password == "password" { // .. } }
The values from the form can be created manually by constructing the form body, or automatically by calling  .parsed_values() on the  FormEvent type created by  onsubmit.
rsx! { form { onsubmit: move |evt: FormEvent| async move { // Prevent the browser from navigating away. evt.prevent_default(); // Extract the form values into our `LoginForm` struct. The `.parsed_values` method // is provided by Dioxus and works with any form element that has `name` attributes. let values: LoginForm = evt.parsed_values().unwrap(); // Call the login endpoint login(Form(values)).await; }, input { r#type: "text", id: "username", name: "username" } label { "Username" } input { r#type: "password", id: "password", name: "password" } label { "Password" } button { "Login" } } }
Form elements must have a "name" attribute which will be used during the deserialization process to identify form fields.
Note that  GET requests will encode the form values in the request URL. This might not work for complex data structures, so it's best practice to use  POST endpoints for handling form data.
Multipart
With some forms, you'll need to handle multiple request bodies in a single request. For example, if your form has file inputs, the browser will automatically create a multi-part request with the form values in one body and then file uploads in another.
Dioxus provides the  MultipartFormData type which will automatically convert  FormEvent objects into proper multi-part requests.
On the client, youd'd convert the  FormEvent with  .into():
rsx! { form { display: "flex", flex_direction: "column", gap: "8px", onsubmit: move |evt| async move { evt.prevent_default(); upload(evt.into()).await; }, label { r#for: "headshot", "Photos" } input { r#type: "file", name: "headshot", multiple: true, accept: ".png,.jpg,.jpeg" } label { r#for: "resume", "Resume" } input { r#type: "file", name: "resume", multiple: false, accept: ".pdf" } label { r#for: "name", "Name" } input { r#type: "text", name: "name", placeholder: "Name" } label { r#for: "age", "Age" } input { r#type: "number", name: "age", placeholder: "Age" } input { r#type: "submit", name: "submit", value: "Submit your resume" } } }
On the server, youd'd use an endpoint that takes  MultipartFormData and then iterate through the fields using  next_field():
#[post("/api/upload-multipart")] async fn upload(mut form: MultipartFormData) -> Result<()> { while let Ok(Some(field)) = form.next_field().await { let name = field.name().unwrap_or("<none>").to_string(); let file_name = field.file_name().unwrap_or("<none>").to_string(); let content_type = field.content_type().unwrap_or("<none>").to_string(); let bytes = field.bytes().await; // ... } Ok(()) }
Currently Dioxus does not support typed  MultipartFormData objects, but it is something we'd like to add in the future.