diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs
index 713eafc..772e8be 100644
--- a/maud_macros/src/parse.rs
+++ b/maud_macros/src/parse.rs
@@ -190,6 +190,10 @@ impl<'cx, 'i> Parser<'cx, 'i> {
                 let name = try!(self.name());
                 try!(self.element(sp, &name));
             },
+            // Shorthand div element
+            [dot!(), ident!(sp, _), ..] => {
+                try!(self.element(sp, "div"));
+            },
             // Block
             [TokenTree::Delimited(_, ref d), ..] if d.delim == DelimToken::Brace => {
                 self.shift(1);
@@ -364,6 +368,7 @@ impl<'cx, 'i> Parser<'cx, 'i> {
             parse_error!(self, sp, "unexpected element, you silly bumpkin");
         }
         self.render.element_open_start(name);
+        try!(self.class_shorthand());
         try!(self.attrs());
         self.render.element_open_end();
         if let [slash!(), ..] = self.input {
@@ -375,6 +380,30 @@ impl<'cx, 'i> Parser<'cx, 'i> {
         Ok(())
     }
 
+    /// Parses and renders the attributes of an element.
+    fn class_shorthand(&mut self) -> PResult<()> {
+        let mut classes = Vec::new();
+        loop {
+            match self.input {
+                [dot!(), ident!(_, _), ..] => {
+                    self.shift(1);
+                    classes.push(try!(self.name()));
+                },
+                _ => break,
+            }
+        }
+        if !classes.is_empty() {
+            self.render.attribute_start("class");
+            let mut s = String::new();
+            for class in classes {
+              s = s + &*class + " ";
+            }
+            self.render.string(s.trim());
+            self.render.attribute_end();
+        }
+        Ok(())
+    }
+
     /// Parses and renders the attributes of an element.
     fn attrs(&mut self) -> PResult<()> {
         loop {
diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs
index 265cc00..52123cb 100644
--- a/maud_macros/tests/tests.rs
+++ b/maud_macros/tests/tests.rs
@@ -330,3 +330,38 @@ fn splice_with_path() {
     html!(s, $inner::name()).unwrap();
     assert_eq!(s, "Maud");
 }
+
+#[test]
+fn class_shorthand() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " span.name { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <span class=\"name\">Lyra</span>!</p>");
+}
+
+#[test]
+fn div_class_shorthand() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " .name { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <div class=\"name\">Lyra</div>!</p>");
+}
+
+#[test]
+fn classes_shorthand() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " span.name.here { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <span class=\"name here\">Lyra</span>!</p>");
+}
+
+#[test]
+fn div_classes_shorthand() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " .name.here { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <div class=\"name here\">Lyra</div>!</p>");
+}
+
+#[test]
+fn div_classes_shorthand_with_attrs() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " .name.here id="thing" { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <div class=\"name here\" id=\"thing\">Lyra</div>!</p>");
+}