Readme
platelet
platelet is an HTML-first templating language.
This repo contains a Rust library for rendering platelet templates.
Why platelet?
Unlike moustache , handlebars , Jinja , Liquid and other templating languages, platelet 's syntax is part of HTML (similar to Vue.js).
This has a few upsides:
Higher level but less powerful than direct string manipulation
The language is natural to read and write when working with HTML, and control flow follows HTML structure
You can use your own HTML formatters and tooling
HTML sanitization is more natural and straightforward
Example
You can explore live examples in the platelet playground
Template
< ul pl-if = " n > 0" >
< li pl-for = " i in [1, 2, 3]" > {{ i }} × {{ n }} = {{ i * n }}</ li >
</ ul >
Context (input)
{ " n" : 7 }
Output
< ul >
< li > 1 × 7 = 7</ li >
< li > 2 × 7 = 14</ li >
< li > 3 × 7 = 21</ li >
</ ul >
More examples
Advanced example
Template templates/index.html
<!doctype html>
< html >
< head >
< title > {{ title }}</ title >
</ head >
< body >
< template pl-for = " b in blogposts" pl-src = " ./blogpost.html" ^blogpost = " b" >
</ template >
</ body >
</ html >
Template templates/blogpost.html
< article >
< img ^src = " blogpost.img_url" />
< div >
< h2 >
< a ^href = " blogpost.link" > {{blogpost.title}}</ a >
</ h2 >
< template pl-html = " blogpost.summary" > </ template >
< date > {{blogpost.date}}</ date >
</ div >
</ article >
< style >
article {
display : flex ;
}
</ style >
Context (input)
{
" title" : " Angus' Blog" ,
" blogposts" : [
{
" img_url" : " ..." ,
" link" : " ..." ,
" summary" : " ..." ,
" title" : " ..." ,
" date" : " 01/11/2025"
} ,
{
" img_url" : " ..." ,
" link" : " ..." ,
" summary" : " ..." ,
" title" : " ..." ,
" date" : " 01/11/2020"
}
]
}
Reference
Syntax
Example
Details
pl- directives
pl-if , pl-for ...
→
^ attributes
^ class, ^ name ...
→
{ { ... } } nodes
{ { user. email } }
→
Expressions
1 + users[ i] . score
→
pl- Directives
HTML Attributes starting with a pl- are special. They are inspired by Vue's directives.
attribute
pl-if
pl-else-if
pl-else
pl-for
pl-html
pl-src
pl-slot
pl-is
Conditionals: pl-if , pl-else-if , pl-else
pl-if will only render this element if the expression is truthy
pl-else-if , used following a pl-if , will only render this element if the expression is truthy
pl-else , used following a pl-if or pl-else-if , will render this element otherwise
< button pl-if = " stock >= 1" > Add to cart</ button >
< button pl-else-if = " stock > 0" > Add to cart (1 item left!)</ button >
< button pl-else disabled > Out of stock</ button >
If applied to a < template > , the template will be and the children rendered.
pl-for
Render element multiple times.
Allows 4 types of expression:
< div pl-for = " item in items" > {{item.text}}</ div >
< div pl-for = " (item, index) in items" > ...</ div >
< div pl-for = " (value, key) in object" > ...</ div >
< div pl-for = " (value, name, index) in object" > ...</ div >
If applied to a < template > , the template will be removed and the children rendered.
pl-html
Set the innerHTML (without sanitization) to the given expression.
To set the outerHTML, apply this to a < template > .
< p pl-html = " markdown" > </ p >
{ " markdown" : " <h1>Content from a CMS</h1>..." }
pl-src
Given a path as a string, renders the template at the path and replaces the element.
< slot pl-src = " ./sidebar.html" ^username = " data.username" >
< p > Some text...</ p >
</ slot >
The attributes set on the element (regular attributes or rendered ^ attributes) are used as the context for rendering the template.
pl-slot
On a < slot > , pl-slot (with an optional name) marks the element as a slot, to be replaced.
On a < template > , pl-slot marks the template content as "what fills that slot".
index.html
< slot pl-src = " layout.html" >
< template pl-slot = " sidebar" >
< ul > ...
</ template >
< template pl-slot = " content" >
< table > ...
</ template >
</ slot >
layout.html
< body >
< nav >
< slot pl-slot = " sidebar" > </ slot >
</ nav >
< main >
< slot pl-slot = " content" > </ slot >
</ main >
</ body >
Output
< body >
< nav >
< ul > ...
</ nav >
< main >
< table > ...
</ main >
</ body >
pl-is
Replace the rendered element's tag with this element, given an expression that returns a string
< slot pl-is = ' i == 0 ? "h1" : "h2"' > {item}</ slot >
^ Attributes
In an HTML attribute, prefixing the attribute with ^ allows you to set the value to a platelet expression.
< a ^href = ' "/products/" + slug' > </ a >
If the expression is false or null , the attribute will not render.
< div
class = " static "
^class = " { active: isActive, 'text-danger': hasError }"
^name = " null"
> </ div >
This will render:
< div class = " static active text-danger" > </ div >
Text Nodes
In an HTML text node, { { variable} } inserts a (sanitized) string.
< h1 > Welcome back {{user.name}}!</ h1 >
If the variable is not defined then an error is returned.
Data type
Rendered as
Number
A number
String
A string
Boolean
true or false
Null
blank
Array
error
Object
error
Expressions
All valid JSON values are valid platelet expressions. On top of this, single-quoted strings 'like this' are allowed for convenience when working with HTML.
Operators
On anything: == , != , && , || , ! , x ? y : z
On numbers: + (addition)
On strings and arrays: + (concatenation)
On objects: + (shallow merge, right hand side overriding)
On numbers: - , * , / , % (mod)
On numbers: > , < , >= , <=
On objects arrays and strings, indexing operator a[ b]
On objects, dot access: { " name" : " angus" } . name
On arrays, objects and strings: len ( z)
Expressions can be bracketed ( 9 + 3 ) / 2 == 6
Truthiness
false , [ ] , " " , { } , null are falsy .
All other values are truthy .