diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs
index 4d747fc..056684e 100644
--- a/maud_macros/src/parse.rs
+++ b/maud_macros/src/parse.rs
@@ -55,6 +55,9 @@ macro_rules! literal {
 macro_rules! ident {
     ($sp:pat, $x:pat) => (TtToken($sp, Token::Ident($x, IdentStyle::Plain)))
 }
+macro_rules! substnt {
+    ($sp:pat, $x:pat) => (TtToken($sp, Token::SubstNt($x, IdentStyle::Plain)))
+}
 macro_rules! keyword {
     ($sp:pat, $x:ident) => (TtToken($sp, ref $x @ Token::Ident(..)))
 }
@@ -167,6 +170,14 @@ impl<'cx, 'i> Parser<'cx, 'i> {
                 let expr = try!(self.splice(tt.get_span()));
                 self.render.splice(expr);
             },
+            [substnt!(sp, ident), ..] => {
+                self.shift(1);
+                // Parse `SubstNt` as `[Dollar, Ident]`
+                // See <https://github.com/lfairy/maud/issues/23>
+                let prefix = TtToken(sp, Token::Ident(ident, IdentStyle::Plain));
+                let expr = try!(self.splice_with_prefix(prefix));
+                self.render.splice(expr);
+            },
             // Element
             [ident!(sp, _), ..] => {
                 let name = try!(self.name());
@@ -295,13 +306,20 @@ impl<'cx, 'i> Parser<'cx, 'i> {
     /// The leading `$` should already be consumed.
     fn splice(&mut self, sp: Span) -> PResult<P<Expr>> {
         // First, munch a single token tree
-        let mut tts = match self.input {
+        let prefix = match self.input {
             [ref tt, ..] => {
                 self.shift(1);
-                vec![tt.clone()]
+                tt.clone()
             },
             [] => parse_error!(self, sp, "expected expression for this splice"),
         };
+        self.splice_with_prefix(prefix)
+    }
+
+    /// Parses and renders a `$splice`, given a prefix that we've already
+    /// consumed.
+    fn splice_with_prefix(&mut self, prefix: TokenTree) -> PResult<P<Expr>> {
+        let mut tts = vec![prefix];
         loop { match self.input {
             // Munch attribute lookups e.g. `$person.address.street`
             [ref dot @ dot!(), ref ident @ ident!(_, _), ..] => {
diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs
index 2695e69..42eb731 100644
--- a/maud_macros/tests/tests.rs
+++ b/maud_macros/tests/tests.rs
@@ -294,3 +294,18 @@ fn call() {
     }).unwrap();
     assert_eq!(s, "DucksGeeseSwans");
 }
+
+#[test]
+fn issue_23() {
+    macro_rules! to_string {
+        ($($x:tt)*) => {{
+            let mut s = String::new();
+            html!(s, $($x)*).unwrap();
+            s
+        }}
+    }
+
+    let name = "Lyra";
+    let s = to_string!(p { "Hi, " $name "!" });
+    assert_eq!(s, "<p>Hi, Lyra!</p>");
+}