Data binding and forms
Data binding
Section titled “Data binding”Templates are static by default. {{attribute}} makes a template read its host element’s attributes, and
props="…" on the export makes attributes reflect as typed properties:
<html-export name="user-card" props="name count:number open:boolean"> <template> <h3>{{name}}</h3> <a href="/users/{{name}}" title="{{ name }} ({{count}} posts)">profile</a> <button disabled="{{off}}">Follow</button> </template></html-export><ui--user-card name="Ada" count="3"></ui--user-card><script> const card = document.querySelector('ui--user-card'); card.count = 4; // reflects to count="4"; only the nodes that mention `count` are patched card.setAttribute('name', 'Grace');</script>- No
eval, no expression language, noinnerHTML. A binding is only ever an attribute name, so it works under a strict CSP and Trusted Types.{{a + b}}is aSyntaxError. - Escaping. Text bindings set a text node’s
data: markup in a value is shown, not parsed. A URL attribute (href,src,action, …) refusesjavascript:/vbscript:/ HTMLdata:URLs (the attribute is removed).on*,styleandsrcdocare never bound (aSyntaxErrorwhen the component is registered). - Efficient updates. The template is stamped once; an attribute change patches only the bound nodes that mention it, so the shadow root’s elements are never re-created.
- Compiled output binds identically (it passes
propsto the same runtime). - Non-goals. No loops or conditionals (use a JS component for those), no two-way binding, no object-valued
props, no bindings in
<template>nested in a template, none in server-rendered roots. Details and the exact rules: HTML syntax.
See it live: examples/data.html. The errors a malformed props or binding raises are in
Errors.
Form-associated components
Section titled “Form-associated components”form-associated on an export makes the component a real form control (static formAssociated and
ElementInternals): it appears in FormData under its name, validates (:invalid, required,
setCustomValidity()), is disabled by a disabled <fieldset>, and resets and restores with the form.
<html-export name="text-field" form-associated form-control="input"> <template><label><slot></slot> <input></label></template></html-export>
<form><ui--text-field name="who" value="Ada" required>Name</ui--text-field></form>form-control="input" names the control in the template that carries the value and the validity (and makes the component delegate focus to it by default, so a browser can focus it when validation fails); without it the
element is the control (el.value = …, or el.internals.setFormValue()). attachInternals() is memoized on every
template class, so a closed shadow root (which needs the internals to be found) and your own subclass share the one
object the platform allows. Enter in a text-like form-control input submits the form as native implicit
submission does (the form’s default button, a disabled one blocking it), and form-role="submit" / "reset" make a
component a submit or reset button (click, Enter and Space; it is the form’s default button and the submit event’s
submitter; a custom element cannot be form.requestSubmit(button)’s argument, so the library fires the event itself
and calls form.submit() unless it was cancelled). Not supported: non-string form values, radio-style groups,
formaction and friends on a component, engines without form-associated custom elements. Reference: HTML syntax;
live: examples/forms.html.