lit-html-brackets
v0.3.0
Published
HTML Template literals with a bracket syntax similar to Angular
Readme
lit-html-brackets
Extension to lit-html that supports a syntax using brackets, similar to Angular's templates.
Overview
const template = ({ isAuthenticated, login, logout, options, refs }) => html`
<label>
<input #rememberMe=${refs} type="checkbox" [(checked::change)]=${bind(options, 'rememberMe')}>
Remember me?
</label>
<button #=${bind(refs, 'loginButton')}
class="login-cta" [class.login-cta--logged-on]=${isAuthenticated}
(click)="${isAuthenticated ? logout : login}" (keyup.enter)=${isAuthenticated ? logout : login}
>
${isAuthenticated ? 'Log out' : 'Log in'}
</button>
`;- Use
[]in attributes to get property binding- Use
[class.foo]to show/hide the classfoodepending on the truthiness of the value - Use
[style.foo]to bind the value to to thefoostyle property
- Use
- Use
()in attributes for event binding- Listeners for
keyup/keydownsupport binding to a single key or a key with modifiers, with slightly different semantics from Angular.
- Listeners for
- Use
[()]for two way binding. This requires use of thebindfunction. - Use
#to get references to the elements. This can be used with#prop=${object}whereobject.propwill be set to the element instance, or#name=${callback}wherecallback(elementRef, 'name')will be called. Thenamecan be empty. - The
bindfunction which can be used with the three types of bindings.[prop]=${bind(obj, propName)}: identical to[prop]=${obj[propName]}(event)=${bind(obj, propName)}: identical to(event)=${e => obj[propName] = e.detail}. This usesCustomEvent#detailand as such only works for custom events, not for browser events.[(prop)]=${bind(obj, propName)}: identical to[prop]=${obj[propName]}combined with(prop-changed)=${() => obj[propName] = elementRef.prop}whereelementRefis the element on which the property is bound.[(prop::some-event)]=${bind(obj, propName)}: identical to[prop]=${obj[propName]}combined with(some-event)=${() => obj[propName] = elementRef.prop}whereelementRefis the element on which the property is bound.#=${bind(obj, propName)}: identical to#propName=${obj}
- All other bindings are left as is, i.e. node bindings are not changed and attributes that don't use
[]or()are simply set as attributes. - The
[],()and[()]syntax only works in attributes with a${}value due to howlit-htmlinternally works.
Motivation
lit-html is awesome but by default it lacks options to set properties or event binding.
The extension provided by lit-html to introduce a Polymer-like syntax for setting properties and event listeners (
property,attribute$andon-event) leads to confusing behaviour, which this extension's syntax ([property],attributeand(event)) doesn't:
This extension defaults to attributes, so if you don't write[]or()anywhere you are really just writing regular HTML, while the lit-html extension makes you set properties instead of attributes:/* The following template behaves differently depending on the render function used: * - The default `render` exposed by lit-html and the `render` function exposed by lit-html-brackets * will set attributes `a` to `"foo"` and `b` to `"bar"`. * - The `render` function exposed by lit-html's extension sets the `a` attribute to `"foo"` but it * sets the `b` property to `"bar"`. */ const template = html`<div a="foo" b=${'bar'}></div>`;
Differences with Angular template syntax
Events listeners should be passed instead of called, that is:
// lit-html-brackets syntax html`<div (click)=${onClick}></div>`vs
<!-- angular syntax --> <div (click)="onClick($event)"></div>Event listeners can be registered with negative modifiers
noshift,noalt,nocontrolandnometa. These will only fire the listener if the modifier is absent.Event listeners are fired even if unspecified modifiers are present. Let's take the example of a listener registered to
keyup.enter. In Angular 5 that listener wouldn't fire forshift+enterkey-ups. In lit-html-brackets that listener will fire. Usekeyup.noshift.enterto get a listener that doesn't fire when shift is pressed.Event listeners in Angular can be bound to window/document events. This is arguably more useful when used with Angular's
@HostBinding('window:scroll')annotation than inside a template<div (window:scroll)="...">. As such, lit-html-brackets doesn't support these global event listeners.Two way binding has to be used with the
bindfunction, otherwise it results in one-way binding. This simply because we need the object and the property key to create two way binding. In Angular's templates, the object is known: the component instance. This is not the case for lit-html-brackets.
