cercis

Template engine for HTML in Rust

19 releases (4 stable)

1.2.0 Jun 5, 2024
1.1.0 May 27, 2024
0.3.1 May 12, 2024
0.2.3 May 5, 2024
0.1.10 May 3, 2024
Download history 23/week @ 2024-06-10 4/week @ 2024-06-17 4/week @ 2024-06-24 2/week @ 2024-07-29 7/week @ 2024-08-26 2/week @ 2024-09-02 52/week @ 2024-09-23

56 downloads per month
Used in 2 crates

MIT license

21KB
285 lines

cercis-preview

Template engine for HTML in Rust

cargo add cercis

Using examples

Formatting

Format the data into a string as in format!() macro

all data is transferred to the template by reference

use cercis::prelude::*;

fn main() {
  let name = "Boris";
  
  let page = rsx!(h1 { "Hello {name}!" });

  // output: <h1>Hello Boris!</h1>
  println!("{}", page.render())
}

Attributes

Attributes are written before the tag content as tag: value

use cercis::prelude::*;

fn main() {
  let text_id = "paragraph";
  let text = "Lorem ipsum";

  let page = rsx!(div {
    class: "container",

    h1 { "Hello World!" }
    p {
      id: "{text_id}",
    
      "{text}"
    }
  });

  // output: <div class='container'><h1>Hello World!</h1><p id='paragraph'>Lorem ipsum</p></div>
  println!("{}", page.render())
}

If branching

Using the usual Rust if syntax, you can create branches

use cercis::prelude::*;

fn main() {
  let num = 8;

  let page = rsx!(div {
    if num == 9 {
      span { "Num is 9" }
    }
    if num == 8 {
      span { "Num is 8" }
    }
  });

  // output: <div><span>Num is 8</span></div>
  println!("{}", page.render())
}

Loops

Using the usual Rust for in you can create loops

use cercis::prelude::*;

fn main() {
  let names = vec!["Boris", "Polina", "Igor"];

  let page = rsx!(ol {
    for name in names {
      li { "{name}" }
    }
  });

  // output: <ol><li>Boris</li><li>Polina</li><li>Igor</li></ol>
  println!("{}", page.render())
}

Component with params

Parameters are declared as normal function parameters

use cercis::prelude::*;

fn main() {
  let text = "Lorem ipsum";

  let page = rsx!(div {
    MyComponent {
        text: text
    }
  });

  // output: <div><p>Lorem ipsum</p></div>
  println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: &'a str) -> Element {
    rsx!(p { "{text}" })
}

Component with option params

If the parameter is an option, then you can omit it when calling the component

use cercis::prelude::*;

fn main() {
  let text = "Lorem ipsum";

  let page = rsx!(div {
    MyComponent {}
    MyComponent {
        text: text
    }
  });

  // output: <div><p>empty</p><p>Lorem ipsum</p></div>
  println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: Option<&'a str>) -> Element {
    let text = text.unwrap_or("empty");

    rsx!(p { "{text}" })
}

Component with children

the component can accept elements example: Element<'a> and children if you name the variable children: Element<'a>

all Element types are optional

use cercis::prelude::*;

fn main() {
    let text = "Lorem ipsum";

    let page = rsx!(div {
      MyComponent { span { "children" } }
      MyComponent {
          text: rsx!(p { "{text}" }),

          span { "children" }
      }
      MyComponent { text: rsx!(p { "my text" }) }
    });

    /* output(formatted):
    <div>
        <div class='container'>
            <div></div>
            <span>children</span>
        </div>
        <div class='container'>
            <div><p>Lorem ipsum</p></div>
            <span>children</span>
        </div>
        <div class='container'>
            <div><p>my text</p></div>
        </div>
    </div>
    */
    println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: Element<'a>, children: Element<'a>) -> Element {
    rsx!(div {
        class: "container",

        div { text }
        children
    })
}

Full page

use cercis::prelude::*;

fn main() {
    // declarate people names
    let names = vec!["Boris", "Polina", "Igor", "Nikita"];

    // create peoples ordered list
    let peoples = rsx!(ol {
        for name in names {
            li { "{name}" }
        }
    });

    // create full page using our Page component
    let page = rsx!(Page {
        title: "Cercis",

        h1 { "Peoples:" }
        // insert element from peoples variable
        peoples
    });

    // render our page to string
    println!("{}", page.render())
}

#[component]
pub fn Page<'a>(title: Option<&'a str>, head: Element<'a>, children: Element<'a>) -> Element {
    const META_CONTENT: &str = "witdh=device-width, initial-scale=1.0";

    rsx!(
        // turn into: <!DOCTYPE html>
        doctype {}
        html {
            head {
                meta { charset: "UTF-8" }
                meta {
                    name: "viewport",
                    // interpolate META_CONTENT const into value like format!() macro
                    content: "{META_CONTENT}",
                }
                head
                // declarate title if exists
                if let Some(title) = title {
                    title { "{title}" }
                }
            }
            body { children }
        }

    )
}

If you have any problems create issue

Dependencies

~0.5–1MB
~24K SLoC