The lit documentation has the following example showing how to set attribute values:
<!-- attribute values -->
<div label=${label}></div>
<button ?disabled=${isDisabled}>Click me!</button>
<input .value=${currentValue}>
<button @click=${this.handleClick()}>
So in the above example label
is set without a dot prefix, but value
uses a dot prefix (.value
).
When do we need to include a dot .
prefix when working with html elements in our lit element templates. Is it only for value
property assignments?
TL;DR: You can use value=${}
or .value=${}
depending on the context and what you want it to do.
This is a little confusing, it's something that catches out a lot of developers. It's not a Lit problem, but part of the spec for the DOM.
Elements in the DOM have attributes and properties - both are sub-values of the object, but they behave in different ways. If you've come from other platforms this is confusing, as most UI controls just have one clear way of setting these kinds of parameters.
An attribute is a string that appears in the HTML, you can set it directly in the HTML:
<div foo="abc"></div>
Or programmatically:
const ele = document.createElement('div');
ele.setAttribute('foo', 'abc');
A property can be any JS type, and isn't reflected in the HTML. You can only set it programmatically:
const ele = document.createElement('div');
ele.bar = 123;
Note that setting an attribute does not set a related property (though loads of corner cases):
const ele = document.createElement('div');
ele.setAttribute('foo', 'abc');
ele.bar = 123;
// foo is only an attribute
console.log(ele.foo); // undefined
// bar is only a property
console.log(ele.getAttribute('bar')); // null, because DOM functions like getAttribute() return null
This can get really confusing, because HTML elements can connect attributes and properties, or have unrelated ones with the same names.
For instance, on <input>
the value
attribute sets the initial value for the input, while the value
property gets and sets the current value. This confuses everyone.
It also means that any templating tool (like Lit) needs a way to set both attributes and properties, and be explicit about which they want in the ouput.
Lit does this by having attributes be the default, and a .
prefix to explicitly set a property instead:
const val = 'abc';
html`<input value=${val}>`;
// Outputs <input value="abc">
// This will set the initial value, but then be ignored once there is user input
html`<input .value=${val}>`;
// Outputs <input> and then does something like:
// this.shadowRoot.querySelector('input').value = val;
// This will change the value on each render, even if the user has changed it
So, to come back to the question:
<input value=...
if you want an initial value for the input but then you want whatever the user has typed<input .value=...
if you want to override the value of the input every time the LitElement render
occurs.Since you touched on the other two, we also have boolean attributes and events.
Booleans are a special case because they don't have a value to unset them. This is probably easiest to explain with an example:
html`<input type="checkbox" checked>`; // Outputs a checked checkbox
// Set it programmatically:
let isChecked = false;
html`<input type="checkbox" checked=${isChecked}>`;
// Outputs <input type="checkbox" checked="false">
// This will render as a CHECKED checkbox, because the string "false" is truthy
// Use the ? prefix
html`<input type="checkbox" ?checked=${isChecked}>`;
// Outputs <input type="checkbox">
isChecked = true;
html`<input type="checkbox" ?checked=${isChecked}>`;
// Outputs <input type="checkbox" checked>
Finally, events are using addEventListener
, with some extra code in Lit so that this
refers to the component.
html`<button @click=${this.handleClick}>`;
// Outputs <button> and then does something like:
this.shadowRoot.querySelector('button').
addEventListener(
'click',
e => this.handleClick(e);
);
// Though you can also specify handler properties like once or capture
Finally, when writing your own components Lit gives you helpers to specify attributes, and create properties that automatically update the component when changed. You're best off going to the Lit docs for more on them.