Htmt 2.3.2
dotnet add package Htmt --version 2.3.2
NuGet\Install-Package Htmt -Version 2.3.2
<PackageReference Include="Htmt" Version="2.3.2" />
paket add Htmt --version 2.3.2
#r "nuget: Htmt, 2.3.2"
// Install Htmt as a Cake Addin #addin nuget:?package=Htmt&version=2.3.2 // Install Htmt as a Cake Tool #tool nuget:?package=Htmt&version=2.3.2
Htmt
A templating library for .NET projects designed to be easy to read, write and have good editor support without needing any additional editor plugins. It fully supports trimming and native AOT compilation.
Features
- Simple syntax: Htmt is a superset of HTML/XML, so you can write your templates in any text editor.
- Interpolation: You can interpolate values from a data dictionary into your templates.
- Modifiers: You can modify the interpolated values using modifiers.
- Conditionals: You can show or hide blocks using simple or complex expressions.
- Partials: You can include other templates inside your templates.
- Loops: You can loop over arrays and objects in your data dictionary.
- Extendable: You can implement custom attribute parsers and expression modifiers.
Example syntax
<!DOCTYPE html>
<html>
<head>
<title x:inner-text="{title}"></title>
</head>
<body>
<h1 x:inner-text="{title}"></h1>
<div class="posts" x:if="posts">
<div x:for="posts" x:as="post">
<h2 class="post-title">
<a x:attr-href="/blog/{post.url}" x:inner-text="{post.title | capitalize}"></a>
</h2>
<div class="post-date" x:inner-text="{post.date | date:yyyy-MM-dd}"></div>
<div class="post-content" x:inner-html="{post.body}"></div>
</div>
</div>
</body>
</html>
Installation
dotnet add package Htmt
Usage
A simple example of how to use Htmt with default configuration to generate HTML output:
var template = "<h1 x:inner-text=\"{title}\"></h1>";
var data = new Dictionary<string, object?> { { "title", "Hello, World!" } };
var parser = new Htmt.Parser { Template = template, Data = data };
var html = parser.ToHtml();
You can also generate XML output via the ToXml()
method.
Attributes
HTMT works by parsing attributes in the template. HTMT attributes start with either x:
or data-htmt-
. The x:
prefix is meant as a shorthand for data-htmt-
, so you can use either one. The
only difference is that x:
is not valid HTML, so if you want to write valid HTML, you should use data-htmt-
.
x:inner-text
or data-htmt-inner-text
Sets the inner text of the element to the value of the attribute.
Htmt template:
<h1 x:inner-text="{title}"></h1>
Results in:
<h1>Hello, World!</h1>
x:inner-html
or data-htmt-inner-html
Sets the inner HTML of the element to the value of the attribute.
Htmt template where content
is <p>Hello, World!</p>
:
<div x:inner-html="{content}"></div>
Results in:
<div>
<p>Hello, World!</p>
</div>
x:outer-text
or data-htmt-outer-text
Sets the outer text of the element to the value of the attribute. This is useful if you want to replace the entire element with text.
Htmt template where title
is Hello, World!
:
<h1 x:outer-text="{title}"></h1>
Results in:
Hello, World!
x:outer-html
or data-htmt-outer-html
Sets the outer HTML of the element to the value of the attribute. This is useful if you want to replace the entire element with HTML.
Htmt template where content
is <p>Hello, World!</p>
:
<div x:outer-html="{content}"></div>
Results in:
<p>Hello, World!</p>
x:inner-partial
or data-htmt-inner-partial
Sets the inner HTML of the element to the value of the attribute, which is a partial template. This is useful if you want to include another template inside the current template.
Htmt template where partial
is <p>Hello, World!</p>
:
<div x:inner-partial="partial"></div>
Results in:
<div>
<p>Hello, World!</p>
</div>
The partial
key has to be inside the Data dictionary, and it has to be a string that contains a valid Htmt template.
The partial will inherit the data dictionary that the parent template has, so you can use the same data in the partial as you can in the parent template.
Inner partials also support interpolated expressions, so you can get partials dynamically, like so:
<div x:inner-partial="parts.{partial}"></div>
Where partial
is { "partial", "something" }
, and then parts.something
would be the partial template it will load.
x:outer-partial
or data-htmt-outer-partial
Sets the outer HTML of the element to the value of the attribute, which is a partial template. This is useful if you want to replace the entire element with another template.
Htmt template where partial
is <p>Hello, World!</p>
:
<div x:outer-partial="partial"></div>
Results in:
<p>Hello, World!</p>
The partial
key has to be inside the Data dictionary, and it has to be a string that contains a valid Htmt template.
The partial will inherit the data dictionary that the parent template has, so you can use the same data in the partial as you can in the parent template.
Outer partials also support interpolated expressions, so you can get partials dynamically, like so:
<div x:outer-partial="parts.{partial}"></div>
Where partial
is { "partial", "something" }
, and then parts.something
would be the partial template it will load.
x:if
or data-htmt-if
Removes the element if the attribute is falsey.
Htmt template where show
is false
:
<div x:if="show">Hello, World!</div>
Results in:
The if
attribute also supports complex boolean expressions, like so:
<div x:if="(show is true) and (title is 'Hello, World!')">Hello, World!</div>
This will only show the element if show
is true
and title
is Hello, World!
. The boolean expression validator
supports the following operators: is
, or
and and
. You can also use parentheses to group expressions,
in case you want to have more complex expressions.
- The
is
operator is used to compare two values, and it supports the following types of values:string
,int
,float
,bool
andnull
. - The
or
operator is used to combine two expressions with an OR operator. - The
and
operator is used to combine two expressions with an AND operator.
x:unless
or data-htmt-unless
Removes the element if the attribute is truthy.
Htmt template where hide
is true
:
<div x:unless="hide">Hello, World!</div>
Results in:
The unless
attribute supports the same boolean expressions as the if
attribute.
x:for
or data-htmt-for
Repeats the element for each item in the attribute.
Htmt template where items
is an array of strings:
<ul>
<li x:for="items" x:as="item" x:inner-text="{item}"></li>
</ul>
Results in:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
Note that the x:as
or data-htmt-as
attribute is optional. If you just want to loop over a data structure,
but you don't care about using the data of each individual iteration, you can omit it.
x:attr-*
or data-htmt-attr-*
(Generic Value Attributes)
Above are all the special attributes that do some logical operation, but you can also use the x:attr-*
attributes to set any attribute on an element to the value of the attribute.
For example, to set the href
attribute of an element, you can use the x:attr-href
attribute:
<a x:attr-href="/blog/{slug}">Hello, World!</a>
Results in:
<a href="/blog/hello-world">Hello, World!</a>
If slug
is hello-world
.
Modifiers
All interpolated values in expressions can be modified using modifiers. Modifiers are applied to the value of the attribute, and they can be chained, like so:
<h1 x:inner-text="{title | uppercase | reverse}"></h1>
Modifiers can also take arguments, like so:
<h1 x:inner-text="{title | truncate:10}"></h1>
date
Formats a date string using the specified format.
<p x:inner-text="{date | date:yyyy-MM-dd}"></p>
uppercase
Converts the value to uppercase.
<p x:inner-text="{title | uppercase}"></p>
lowercase
Converts the value to lowercase.
<p x:inner-text="{title | lowercase}"></p>
capitalize
Capitalizes the first letter of the value.
<p x:inner-text="{title | capitalize}"></p>
reverse
Reverses the value.
<p x:inner-text="{title | reverse}"></p>
truncate
Truncates the value to the specified length.
<p x:inner-text="{title | truncate:10}"></p>
count
Returns the count of the value, if the value is a IEnumerable
or string
.
<p x:inner-text="{items | count}"></p>
Extending
Attribute Parsers
You can add (or replace) attribute parsers in Htmt by adding them to the AttributeParsers
array,
when creating a new instance of the Parser
class.
var parser = new Htmt.Parser
{
Template = template,
Data = data,
AttributeParsers = [
new MyCustomAttributeParser()
]
};
A custom attribute parser must extend the BaseAttributeParser
parser, like so:
public class CustomAttributeParser : BaseAttributeParser
{
public override string XTag => "//*[@x:custom or @data-htmt-custom]";
public override void Parse(XmlNodeList? nodes)
{
foreach (XmlNode node in nodes)
{
// You can parse expressions here with ParseExpression(), and
// do anything you want with the nodes as you'd otherwise do with XmlDocument stuff.
}
}
}
The Parse
method is where the attribute parser should do its work, and the XTag
property should return the xtag pattern for the nodes it should parse.
To get an array of default attribute parsers, you can call Htmt.Parser.DefaultAttributeParsers()
,
if you want to add your custom attribute parsers to the default ones, but you can also mix and match however you like.
List of built-in attribute parsers
Htmt.AttributeParsers.InnerTextAttributeParser
- Parses thex:inner-text
/data-htmt-inner-text
attribute.Htmt.AttributeParsers.InnerHtmlAttributeParser
- Parses thex:inner-html
/data-htmt-inner-html
attribute.Htmt.AttributeParsers.OuterTextAttributeParser
- Parses thex:outer-text
/data-htmt-outer-text
attribute.Htmt.AttributeParsers.OuterHtmlAttributeParser
- Parses thex:outer-html
/data-htmt-outer-html
attribute.Htmt.AttributeParsers.InnerPartialAttributeParser
- Parses thex:inner-partial
/data-htmt-inner-partial
attribute.Htmt.AttributeParsers.OuterPartialAttributeParser
- Parses thex:outer-partial
/data-htmt-outer-partial
attribute.Htmt.AttributeParsers.IfAttributeParser
- Parses thex:if
/data-htmt-if
attribute.Htmt.AttributeParsers.UnlessAttributeParser
- Parses thex:unless
/data-htmt-unless
attribute.Htmt.AttributeParsers.ForAttributeParser
- Parses thex:for
/data-htmt-for
attribute.Htmt.AttributeParsers.GenericValueAttributeParser
- Parses thex:attr-*
/data-htmt-attr-*
attributes.
Modifiers
You can add (or replace) modifiers in Htmt by adding them to the Modifiers
array,
when creating a new instance of the Parser
class.
var parser = new Htmt.Parser
{
Template = template,
Data = data,
Modifiers = [
new MyCustomModifier()
]
};
A custom modifier must implement the IExpressionModifier
interface:
public interface IExpressionModifier
{
public string Name { get; }
public object? Modify(object? value, string? args = null);
}
The Modify
method is where the modifier should do its work, and the Name
property should return the name of the modifier.
To get an array of default modifiers, you can call Htmt.Parser.DefaultExpressionModifiers()
,
if you want to add your custom modifiers to the default ones, but you can also mix and match however you like.
List of built-in modifiers
Htmt.ExpressionModifiers.DateExpressionModifier
- Formats a date string using the specified format.Htmt.ExpressionModifiers.UppercaseExpressionModifier
- Converts the value to uppercase.Htmt.ExpressionModifiers.LowercaseExpressionModifier
- Converts the value to lowercase.Htmt.ExpressionModifiers.CapitalizeExpressionModifier
- Capitalizes the first letter of the value.Htmt.ExpressionModifiers.ReverseExpressionModifier
- Reverses the value.Htmt.ExpressionModifiers.TruncateExpressionModifier
- Truncates the value to the specified length.Htmt.ExpressionModifiers.CountExpressionModifier
- Returns the count of the value.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.3.2 | 120 | 11/7/2024 |
2.3.1 | 95 | 11/7/2024 |
2.3.0 | 88 | 11/7/2024 |
2.2.0 | 89 | 11/6/2024 |
2.1.3 | 104 | 11/3/2024 |
2.1.2 | 94 | 11/3/2024 |
2.1.1 | 89 | 11/3/2024 |
2.1.0 | 95 | 11/2/2024 |
2.0.1 | 84 | 10/29/2024 |
2.0.0 | 113 | 10/27/2024 |
1.2.2 | 87 | 10/22/2024 |
1.2.1 | 79 | 10/22/2024 |
1.2.0 | 113 | 10/20/2024 |
1.1.1 | 113 | 10/12/2024 |
1.1.0 | 90 | 10/12/2024 |
1.0.3 | 100 | 10/11/2024 |
1.0.1 | 92 | 10/11/2024 |
1.0.0 | 92 | 10/11/2024 |
Fixed a bug where partials with multiple root nodes break silently.