diff --git a/CHANGELOG.md b/CHANGELOG.md
index c810674..9364c49 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
 
 - Support `no_std` + `alloc`.
   [#278](https://github.com/lambda-fairy/maud/issues/278)
+- Provide Tide support.
+  [#280](https://github.com/lambda-fairy/maud/pull/280) 
 
 ## [0.22.2] - 2021-01-09
 
diff --git a/docs/content/web-frameworks.md b/docs/content/web-frameworks.md
index 916b4fc..0eb52d0 100644
--- a/docs/content/web-frameworks.md
+++ b/docs/content/web-frameworks.md
@@ -1,12 +1,13 @@
 # Web framework integration
 
 Maud includes support for these web frameworks:
-[Actix], [Iron], [Rocket], and [Rouille].
+[Actix], [Iron], [Rocket], [Rouille], and [Tide].
 
 [Actix]: https://actix.rs/
 [Iron]: http://ironframework.io
 [Rocket]: https://rocket.rs/
 [Rouille]: https://github.com/tomaka/rouille
+[Tide]: https://docs.rs/tide/
 
 # Actix
 
@@ -142,3 +143,37 @@ fn main() {
     });
 }
 ```
+
+# Tide
+
+Tide support is available with the "tide" feature:
+
+```toml
+# ...
+[dependencies]
+maud = { version = "*", features = ["tide"] }
+# ...
+```
+
+This adds an implementation of `From<PreEscaped<String>>` for the `Response` struct.
+Once provided, callers may return results of `html!` directly as responses:
+
+```rust,no_run
+use maud::html;
+use tide::Request;
+use tide::prelude::*;
+
+#[async_std::main]
+async fn main() -> tide::Result<()> {
+    let mut app = tide::new();
+    app.at("/hello/:name").get(|req: Request<()>| async move {
+        let name: String = req.param("name")?.parse()?;
+        Ok(html! {
+            h1 { "Hello, " (name) "!" }
+            p { "Nice to meet you!" }
+        })
+    });
+    app.listen("127.0.0.1:8080").await?;
+    Ok(())
+}
+```
diff --git a/doctest/Cargo.toml b/doctest/Cargo.toml
index 078fbe7..25d575f 100644
--- a/doctest/Cargo.toml
+++ b/doctest/Cargo.toml
@@ -8,10 +8,15 @@ edition = "2018"
 actix-web = "3"
 ammonia = "3"
 iron = "0.6"
-maud = { path = "../maud", features = ["actix-web", "iron", "rocket"] }
+maud = { path = "../maud", features = ["actix-web", "iron", "rocket", "tide"] }
 pulldown-cmark = "0.8"
 rocket = "0.4"
 rouille = "3"
+tide = "0.16"
+
+[dependencies.async-std]
+version = "1.9.0"
+features = ["attributes"]
 
 [lib]
 path = "lib.rs"
diff --git a/maud/Cargo.toml b/maud/Cargo.toml
index 3fa34fa..eb04fb5 100644
--- a/maud/Cargo.toml
+++ b/maud/Cargo.toml
@@ -24,6 +24,7 @@ iron = { version = ">= 0.5.1, < 0.7.0", optional = true }
 rocket = { version = ">= 0.3, < 0.5", optional = true }
 futures-util = { version = "0.3.0", optional = true, default-features = false }
 actix-web-dep = { package = "actix-web", version = ">= 2, < 4", optional = true, default-features = false }
+tide = { version = "0.16.0", optional = true }
 
 [dev-dependencies]
 trybuild = { version = "1.0.33", features = ["diff"] }
diff --git a/maud/src/lib.rs b/maud/src/lib.rs
index a2f1499..96d7c9d 100644
--- a/maud/src/lib.rs
+++ b/maud/src/lib.rs
@@ -237,3 +237,19 @@ mod actix_support {
         }
     }
 }
+
+#[cfg(feature = "tide")]
+mod tide_support {
+    use crate::PreEscaped;
+    use alloc::string::String;
+    use tide::{http::mime, Response, StatusCode};
+
+    impl From<PreEscaped<String>> for Response {
+        fn from(markup: PreEscaped<String>) -> Response {
+            Response::builder(StatusCode::Ok)
+                .body(markup.into_string())
+                .content_type(mime::HTML)
+                .build()
+        }
+    }
+}