Markup.js
Powerful JavaScript templates
Install / Use
/learn @adammark/Markup.jsREADME
Markup.js — Powerful JavaScript templates
Markup.js is a simple yet surprisingly powerful template system for JavaScript.
Why Markup.js?
Markup.js takes the pain out of converting structured data into HTML markup or other text formats. Its intuitive syntax and small footprint (only 1.9KB minified and gzipped) make it the perfect choice for your JavaScript app. Plus there are no dependencies.
Usage
Include <script src="markup.min.js"></script>.
Markup.js has a single function: Mark.up(template, context). Here's a basic
example that shows how template, a string, is injected with properties of
context, an object:
var context = {
name: {
first: "John",
last: "Doe"
}
};
var template = "Hi, {{name.first}}!";
var result = Mark.up(template, context); // "Hi, John!"
You can format any kind of objects, including functions with exposed properties:
var context = {
person: new Person("Adam")
};
var template = "Hi, {{person.name}}!";
var result = Mark.up(template, context); // "Hi, Adam!"
Object notation
You can access object properties with simple dot notation:
var context = {
name: "John Doe",
addr: {
street: "1 Maple Street",
city: "Pleasantville",
zip: {
main: "12345",
ext: "6789"
}
}
};
var template = "{{name}} lives at {{addr.street}} in {{addr.city}}.";
var result = Mark.up(template, context);
// "John Doe lives at 1 Maple Street in Pleasantville."
Or you can use nested tags:
var template = "{{name}} lives at {{addr}}{{street}} in {{city}}.{{/addr}}";
var result = Mark.up(template, context);
// "John Doe lives at 1 Maple Street in Pleasantville."
Or you can use a combination of nested tags and dot notation:
var template = "ZIP: {{addr}}{{zip.main}}-{{zip.ext}}{{/addr}}";
var result = Mark.up(template, context);
// "ZIP: 12345-6789"
Array notation
Array members can be accessed by index. For example:
var context = {
name: "John Doe",
colors: ["Red", "Blue", "Green"]
};
var template = "Favorite color: {{colors.0}}";
var result = Mark.up(template, context);
// "Favorite color: Red"
You can mix array index notation and object property notation in the same expression:
var context = {
name: "John Doe",
friends: [{name: "Bob"}, {name: "Fred"}]
};
var template = "Best friend: {{friends.0.name}}";
var result = Mark.up(template, context);
// "Best friend: Bob"
Loops
If a tag resolves to an array, the array is iterated. A single dot refers to the current iteration context:
var context = {
name: "John Doe",
brothers: ["Jack", "Joe", "Jim"]
};
var template = "<ul>{{brothers}}<li>{{.}}</li>{{/brothers}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>Jack</li><li>Joe</li><li>Jim</li></ul>"
var context = {
user: {
contacts: ["John", "Jane"]
}
};
var template = "<ul>{{user.contacts}}<li>{{.}}</li>{{/user.contacts}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>John</li><li>Jane</li></ul>"
When looping through an array of objects, object properties can be referenced by name:
var context = {
name: "John Doe",
sisters: [{name: "Jill"}, {name: "Jen"}]
};
var template = "<ul>{{sisters}}<li>{{name}}</li>{{/sisters}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>Jill</li><li>Jen</li></ul>"
Dot notation works inside loops as well:
var context = {
sisters: [
{name: {first: "Jill", last: "Doe"}},
{name: {first: "Jen", last: "Doe"}}
]
};
var template = "<ul>{{sisters}}<li>{{name.first}}</li>{{/sisters}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>Jill</li><li>Jen</li></ul>"
Loop counters
Inside a loop, a single hash sign refers to the current iteration index (0...n-1) and a double hash sign refers to the current iteration count (1...n):
var template = "{{sisters}} {{#}}-{{name.first}} {{/sisters}}";
// " 0-Jill 1-Jen "
var template = "{{sisters}} {{##}}-{{name.first}} {{/sisters}}";
// " 1-Jill 2-Jen "
This is useful for applying conditional formatting, as described below, and for creating numbered lists.
Pipes
Pipes are a powerful way to transform variables. Here's a simple example:
var context = {
name: "John Doe",
alias: " J-Do ",
phone: null,
gender: "male",
age: 33.33,
vitals: [68, 162.5, "AB"],
brothers: ["Jack", "Joe", "Jim"],
sisters: [{name: "Jill"}, {name: "Jen"}],
jiggy: true
};
var template = "Name: {{name|upcase}}";
var result = Mark.up(template, context);
// "Name: JOHN DOE"
A pipe can accept arguments. For example, the blank pipe accepts a value to
display if the piped input is null or empty:
var template = "Phone: {{phone|blank>N/A}}";
var result = Mark.up(template, context);
// "Phone: N/A"
The choose pipe accepts two strings and returns one of them depending on
whether the piped input is true or false:
var template = "John is jiggy: {{jiggy|choose>Yes>No}}";
var result = Mark.up(template, context);
// "John is jiggy: Yes"
Pipes can be applied to any kind of data structure:
// get the second value in an array and round it
var template = "Weight: {{vitals.1|round}} lbs.";
var result = Mark.up(template, context);
// "Weight: 163 lbs."
// sort an array of strings, then upcase each string
var template = "<ul>{{brothers|sort}}<li>{{.|upcase}}</li>{{/brothers}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>JACK</li><li>JIM</li><li>JOE</li></ul>"
// reverse an array of objects, then chop each name property
var template = "<ul>{{sisters|reverse}}<li>{{name|chop>2}}</li>{{/sisters}}</ul>";
var result = Mark.up(template, context);
// "<ul><li>Je...</li><li>Ji...</li></ul>"
Chaining pipes
Variables can be passed through multiple pipes. Here are two simple examples:
var template = "Alias: {{alias|trim|downcase}}";
var result = Mark.up(template, context);
// "Alias: j-do"
var template = "Age: {{age|more>75|choose>Oldish>Youngish}}";
var result = Mark.up(template, context);
// "Age: Youngish"
You can get very creative with pipes:
var template = "Bros: {{brothers|sort|limit>2|join> & }}";
var result = Mark.up(template, context);
// "Bros: Jack & Jim"
Built-in pipes
Markup.js comes with more than 40 built-in pipes:
empty (obj): Test for an empty array, empty string, null, undefined, or 0. {{if apples|empty}}
notempty (obj): Test for the presence of a value. {{if apples|notempty}} or simply {{if apples}}
more (obj, n): Test if a number, [iterator][1], or array is greater than n. {{if articles|more>100}} {{if #|more>10}}
less (obj, n): Test if a number, [iterator][1], or array is less than n. {{if age|less>21}}
ormore (obj, n): Test if a number, [iterator][1], or array is greater than or equal to n. {{if age|ormore>18}}
orless (obj, n): Test if a number, [iterator][1], or array is less than or equal to n. {{if age|orless>55}}
between (obj, n1, n2): Test if a number, [iterator][1] or array is between n1 and n2, inclusive. {{if age|between>18>35}}
equals (obj, str): Test for equality (==). {{if name|equals>Adam}} {{if age|equals>35}}
notequals (obj, str): Test for inequality (!=). {{if name|notequals>Adam}}
like (str, str): Test for a pattern match (case-insensitive). {{if name|like>Adam}} {{if name|like>a.*}}
notlike (str, str): Test for a non-match (case-insensitive). {{if name|notlike>Adam}}
blank (str, str): Display a default value for a null or empty string. {{title|blank>Untitled}}
upcase (str): Upper-case a string. {{name|upcase}}
downcase (str): Lower-case a string. {{name|downcase}}
capcase (str): Capitalize the first letter in each word. {{title|capcase}}
chop (str, n): Chop a string to n chars followed by "..." if n < string length. {{description|chop>100}}
tease (str, n): Chop a string to n words followed by "..." if n < word count. {{summary|tease>15}}
trim (str): Trim leading and trailing white space from a string. {{article|trim}}
pack (str): Trim and normalize white space in a string. {{article|pack}}
round (num): Round a number. {{age|round}}
clean (str): Strip HTML/XML tags from a string. {{article|clean}}
length (obj): Get the length of an array, string, or [iterator][1]. {{apples|length}} {{#|length}}
size (obj): Alias of length. {{apples|size}} {{#|size}}
reverse (arr): Reverse an array.* {{articles|reverse}} ... {{/articles}}
join (arr [, str]): Join an array with "," or with the given token. {{names|join> + }}
limit (arr, n1 [, n2]): Limit an array to n1 items beginning at index n2 (or 0). {{contacts|limit>10}} ... {{/contacts}}
split (str [, str]): Split a string on "," or by the given token. {{names|split>;}} {{.}} {{/names}}
choose (bool, str [, str]): Output one value if truthy, another if falsy. {{user.passed|choose>Pass>Fail}}
toggle (obj, str, str [,str]): Switch one string value for another. {{gender|toggle>M,F>Boy,Girl>N/A}}
sort (arr [, str]): Sort an array, optionally by object property name.* {{users|sort>firstname}} ... {{/users}}
fix (num, n): Format a number to n decimal places. {{weight|fix>1}}
mod (num, n): Get the remainder of a number or [iterator][1] divided by n. {{rows|mod>10}}
divisible (num, n): Test if a number or [iterator][1] is perfectly divisible by n. {{if #|divisible>3}}
even (num): Test if a number or [iterator][1] is even. {{if #|even}}
odd (num): Test if a number or [iterator][1] is odd. `{{if #|odd}
Related Skills
node-connect
349.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
