kensington
v0.9.3
Published
This template engine is a way to create html via nested method calls. Each tag is a method on a TemplateEngine instance which can receive an object literal of attributes and their values, and/or content. The output is a nicely formatted html string.
Maintainers
Readme
This template engine is a way to create html via nested method calls. Each tag is a method on a TemplateEngine instance which can receive an object literal of attributes and their values, and/or content. The output is a nicely formatted html string.
- arguments can be an object of attributes, content (string, element, or array of either), or both
- nested attributes are converted to kebab-case
{ data: { bs: { toggle: 'collapse' } } }becomesdata-bs-toggle="collapse" - camelCase attibute become kebabcase
{ dataBsToggle: 'collapse' }becomesdata-bs-toggle="collapse" - attributes are validated against those found here
- attributes with a boolean value will either be included or not:
t.input({ type: 'checkbox', checked: true })becomes<input type="checkbox" checked>or<input type="checkbox" />ifcheckedis false - Global attributes are always allowed, along with
aria-*anddata-*attributes. - Additional namespaces (like
hxwhen using htmx) can be added by passing theadditionalNamespacesproperty to the constructor validationLevelcan be set tooff,warn, orerror.- the
.literalmethod allows you to pass in html as a string. .htmlWithDocTypeis the same as.html, but adds the<!DOCTYPE html>tag to the beginning of the string.- call
.toString()on the outermost method to expicitly convert to string. This can often be omitted if the output is sent as a string. - string interpolation automatically converts the tag to string
`${t.html(t.body('hello'))}` - you can add your own custom elements:
- extend the
Kensingtonclass with your own - set a property equal to
this.createCustomTag()with the following argumentstagName- the name that is used in the<some-custom-element></some-custom-element>allowedAttributes- an optional object of allowed attribute names and types. Global and data/aria attributes are always allowed
- extend the
Example
// TypeScript
import Kensington from 'kensington';
import type { ContentMethod } from 'kensington';
declare module 'kensington' {
interface NameSpaceAttributes {
[key: `hx${string}`]: string | object
}
}
class MyTemplateEngine extends Kensington {
someCustomElement: ContentMethod<{ someCustomAttribute?: boolean | 42 }> = this.createCustomTag('custom-element', { 'some-custom-attribute': [Boolean, 42] });
}// JavaScript
import Kensington from 'kensington.js';
class MyTemplateEngine extends Kensington {
someCustomElement = this.createCustomTag('some-custom-element', { 'some-custom-attribute': [Boolean, 42] });
}const t = new MyTemplateEngine({ validationLevel: 'warn', additionalNamespaces: ['hx'] });
const html = t.htmlWithDoctype({ lang: 'en' }, [
t.head(t.title('My Page Title')),
t.body(
t.main({ class: 'container' }, [
t.h1('My Great Project'),
t.h3({ class: 'small' }, 'a new way'),
t.hr({ class: 'fancy-line' }),
t.section([
'To Do List',
t.ul([
t.li({
data: {
bs: {
toggle: 'collapse',
target: '#some-id',
},
},
ariaExpanded: 'false',
}, 'this'),
t.li([
t.input({ id: 'coolness', type: 'checkbox', checked: isCool }),
t.label({ for: 'coolness'}, 'Cool?')
]),
t.literal('<li>some regular html</li>'),
]),
]),
]),
),
]).toString();/* Generated html
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page Title</title>
</head>
<body>
<main class="container">
<h1>My Great Project</h1>
<h3 class="small">a new way</h3>
<hr class="fancy-line">
<section>
To Do List
<ul>
<li data-bs-toggle="collapse" data-bs-target="#some-id" aria-expanded="false">this</li>
<li>
<input id="coolness" type="checkbox">
<label for="coolness">Cool?</label>
</li>
<li>some regular html</li>
</ul>
</section>
</main>
</body>
</html>
*/// import instance directly if you don't need customization
import { t } from 'kensington';TODO
- type declaration file for custom instance
- validate/type data and aria attributes
- skip validation per tag (maybe a bad idea)
- readme demos express integration
- mention use of html-validate
- what version of node/js is necessary?
- comments
- better namespace non-tag methods to avoid potential future collisions
- better monkey patching
- html to kensington transpiler?
- conditionally allow attributes based on other attributes (multiple allowed only on inputs of type="file")
- build dist for browser
- make line break -> optional
- pass logger to constructor instead of console.log
- better format css
- configurable indentation level
- use private class methods
- stress testing with large data sets
- methods for entities ( )
