You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jan 9, 2025. It is now read-only.
Copy file name to clipboardExpand all lines: README.md
+238Lines changed: 238 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,3 +7,241 @@ This library is heavily inspired by [`lit-html`](https://github.com/Polymer/lit-
7
7
- To re-use code we're using with [@github/template-parts](https://github.com/github/template-parts/) which is in production at GitHub.
8
8
- To align closer to the `Template Parts` whatwg proposal. By using [@github/template-parts](https://github.com/github/template-parts/) we aim to closely align to the Template Parts proposal, hopefully one day dropping the dependency on [@github/template-parts](https://github.com/github/template-parts/).
9
9
10
+
### Basic Usage
11
+
12
+
This library comes with a set of exports, the main two being `html` and `render`.
13
+
14
+
`html` is a ["tagged template" function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). Rather than calling it, you "tag" a template string with `html` and it will return a `TemplateResult` which can be used to render HTML safely, on the client side.
jtml interpolates placeholder expressions in special ways across the template. Depending on where you put a placeholder expression (the `${}` syntax is a placeholder expression) depends on what it does. _Importantly_ "Attributes" behave differently to "Nodes". Here is a comprehensive list:
35
+
36
+
#### Attributes
37
+
38
+
HTML Attributes can contain placeholder expressions, but these _must_ be inside the quoted part of the attribute. The name of an Attribute cannot use placeholder expressions, only the value.
39
+
40
+
```js
41
+
import {html, render} from'@github/jtml'
42
+
43
+
constclassName=`red-box`
44
+
45
+
html`<pclass="${className}"></p>`// This is valid
46
+
47
+
html`<pclass=${className}></p>`// !! This is INVALID!
48
+
html`<p${attr}="test"></p>`// !! This is INVALID!
49
+
```
50
+
51
+
##### Boolean Values
52
+
53
+
If an attribute maps to a ["boolean attribute"](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#boolean_attributes), and the attribute value consists _solely_ of a placeholder expression which evaluates to a boolean, then this can be used to toggle the attribute on or off. For example:
render(input(false), document.body) // Will render `<input />`
62
+
render(input(true), document.body) // Will render `<input required />`
63
+
64
+
render(div(true), document.body) // Will render `<div></div>`
65
+
render(div(false), document.body) // Will render `<div></div>`
66
+
```
67
+
68
+
##### Multiple values, whitespace
69
+
70
+
If an attribute consists of multiple placeholder expressions, these will all be mapped to strings. Any included whitespace is also rendered as you might expect. Here's an example:
Any placeholder expression which evaluates to an Array/Iterable is joined with spaces (`Array.from(value).join(' ')`). This means you can pass in an Array of strings and it'll be rendered as a space separated list. These can still be mixed with other placeholder expressions or static values. An example:
If an attributes name begins with`on`, and the value consists of a single placeholder expression that evaluates to a function, then this will become an Event Listener, where the event name is the attribute name without the `on`, so for example:
105
+
106
+
```js
107
+
import {html, render} from '@github/jtml'
108
+
109
+
const handleClick = e => console.log('User clicked!')
The event name can be any event name that is also possible as an attribute, for example `onloaded` will listen for the `loaded` event, `onwill-load` will bind to the `will-load` event. Special characters such as `:`s are not allowed as attribute names, and as such you cannot bind to an event name with these special characters using this pattern.
117
+
118
+
#### Nodes
119
+
120
+
Placeholder expressions can also be put where an HTML node might be - in other words inside a tag, rather than inside an attribute. These behave differently to placeholder expressions inside attribute values:
121
+
122
+
##### HTML Escaping
123
+
124
+
Any HTML inside a string is automatically escaped. Values get added as `Text` nodes, meaning it is impossible to inject HTML unless you explicitly want to, making them safe for XSS. This is not manually handled by the library, but is core to the design - meaning the browser handles this escaping! An example:
If a placeholder expression evaluates to a sub template, then that sub template will be rendered and added to as a child to the node, in the position you'd expect:
138
+
139
+
```js
140
+
import {html, render} from '@github/jtml'
141
+
142
+
const embolden = word => html`<strong>${word}</strong>`
Any placeholder expression which evaluates to an Array/Iterable is evaluated per-item. If a single item is a Document Fragment or Sub Template then it will be rendered as you might expect, otherwise it is treated as a String and gets added as a `Text` node. All of the contents of the Array will be rendered as one. Some examples:
For more advanced behaviours, a function can be wrapped with the `directive` function to create a `Directive` which gets to customize the rendering flow. jtml also includes some built in directives (see below).
190
+
191
+
A directive must follow the following signature. It can take any number of arguments (which are ignored) and must return a function which receives the TemplatePart:
192
+
193
+
```typescript
194
+
type Directive = (...values: unknown[]) => (part: TemplatePart) => void
195
+
```
196
+
197
+
Here's an example of how a directive might work:
198
+
199
+
```js
200
+
import {html, render, directive} from '@github/jtml'
201
+
202
+
// A directive can take any number of arguments, and must return a function that takes a `TemplatePart`.
203
+
const renderLater = directive((text, ms) => part => {
// After 1000ms, changes to `<div>Hello world</div>`
212
+
```
213
+
214
+
### Built in Directives
215
+
216
+
### until
217
+
218
+
jtml ships with a built-in directive for handling Promise values, called `until`. `until` takes any number of Promises, and will render them, right to left, as they resolve. This is useful for passing in asynchronous values as the first arguments, timeout messages as the middle value, and synchronous values for the placeholder values, like so:
0 commit comments