Horrorshow: A no-longer POC html template library


Horrorshow is a macro-based HTML templating library. For those of you who saw the last post, horrorshow has become quite a bit more useful.


Project: GitHub, crates.io
Docs: https://stebalien.github.io/horrorshow-rs/horrorshow/


  • Works on stable.
  • Built-in html escaping (that should be audited by someone who knows what they are doing…).
  • Can render into existing strings and io writers.
  • fast (compiles to assembly).
  • Composable.

Non features:

  • Really unhelpful errors. Unfortunately, there’s no way to tell rust: “don’t look in this ugly macro code for type errors, assume I meant every word of this macro code and the error is elsewhere.”
  • To be able to return a template, it needs to be boxed. This is because templates are actually closures. However, this is only true of returned templates; you don’t need to allocate when rendering locally.


extern crate horrorshow;

use horrorshow::{RenderBox, Template};

fn render_post(post: Post) -> Box<RenderBox> {
    let Post { title, body, tags } = post;
    box_html! {
        article {
            header(class="post-header") {
                h1 : title;
                ul {
                    |t| tags.iter().fold(t, |t, tag| t << html! {
                        li : tag

                    // You should  be able to write the following but rust doesn't
                    // re-borrow when using binary operators (gh#25753).
                    |t| for tag in tags {
                        t << html! { li : tag };
            section(class="post-body") : body;

fn render<I: Iterator<Item=Post>>(title: &str, posts: I) -> String {
    (html! {
        : raw!("<!DOCTYPE html>");
        html {
            head {
                title : title
            body {
                main {
                    header { h1 : title }
                    section(id="posts") {
                        |t| posts.fold(t, |t, post| t << render_post(post));

struct Post {
    title: String,
    tags: Vec<String>,
    body: String,

fn main() {
    let posts = vec![
        Post {
            title: String::from("First Post"),
            tags: vec![String::from("first post")],
            body: String::from("My Test Post"),
        Post {
            title: String::from("Second Post"),
            tags: vec![],
            body: String::from("My Second Test Post"),
    println!("{}", render("my blog", posts.into_iter()));


<!DOCTYPE html>
        <title>my blog</title>
                <h1>my blog</h1>
            <section id="posts">
                    <header class="post-header">
                        <h1>First Post</h1>
                            <li>first post</li>
                    <section class="post-body">My Test Post</section>
                    <header class="post-header">
                        <h1>Second Post</h1>
                    <section class="post-body">My Second Test Post</section>

If you have any comments on the current error handling design, please post them here: Error Handling Design in Horrorshow


a no-longer POC

Ahh yes, just like all code: you think it’s a throwaway, but then it stays around forever… :smile:


It was too fun to put down. Also, I don’t feel like fixing the my patched version of ruhoh so I decided to write a static blogging engine from scratch (TBD)…