Template system with data binding, conditional rendering, list iteration, and event handling capabilities.
Polymer's template binding syntax for connecting element properties to template content.
/**
* One-way binding: [[property]] - data flows from element to template
* Two-way binding: {{property}} - data flows both ways
* Attribute binding: attribute="[[property]]" or attribute$="[[property]]"
* Event binding: on-event="handler"
*/Usage Examples:
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
class BindingExample extends PolymerElement {
static get is() { return 'binding-example'; }
static get template() {
return html`
<!-- One-way text binding -->
<div>Hello [[name]]!</div>
<!-- Two-way input binding -->
<input value="{{inputValue::input}}" placeholder="Type here">
<div>You typed: [[inputValue]]</div>
<!-- Attribute binding -->
<img src="[[imageUrl]]" alt="[[imageAlt]]">
<div class$="[[computeClass(active)]]">Status</div>
<!-- Boolean attribute binding -->
<button disabled$="[[!canSubmit]]">Submit</button>
<!-- Event binding -->
<button on-click="handleClick">Click me</button>
<input on-keydown="handleKeydown">
<!-- Property binding to child elements -->
<child-element data="[[complexData]]" on-data-changed="handleDataChange"></child-element>
<!-- Computed binding -->
<div>Total: [[computeTotal(items.*)]]</div>
`;
}
static get properties() {
return {
name: String,
inputValue: String,
imageUrl: String,
imageAlt: String,
active: Boolean,
canSubmit: Boolean,
complexData: Object,
items: Array
};
}
computeClass(active) {
return active ? 'active' : 'inactive';
}
computeTotal(changeRecord) {
return changeRecord.base.reduce((sum, item) => sum + item.value, 0);
}
handleClick(e) {
console.log('Button clicked:', e);
}
handleKeydown(e) {
if (e.key === 'Enter') {
console.log('Enter pressed');
}
}
handleDataChange(e) {
console.log('Child data changed:', e.detail.value);
}
}Element for conditionally rendering template content based on boolean conditions.
/**
* Conditionally stamps template content based on if property
*/
class DomIf extends PolymerElement {
/** Boolean condition that controls template rendering */
if: boolean;
/** Whether to destroy and recreate content when condition changes */
restamp: boolean;
}Usage Examples:
class ConditionalExample extends PolymerElement {
static get is() { return 'conditional-example'; }
static get template() {
return html`
<button on-click="toggleShow">Toggle Content</button>
<!-- Basic conditional -->
<template is="dom-if" if="[[showContent]]">
<div>This content is conditionally shown</div>
</template>
<!-- Conditional with restamp -->
<template is="dom-if" if="[[showForm]]" restamp>
<form>
<input type="text" placeholder="This form is recreated each time">
<button type="submit">Submit</button>
</form>
</template>
<!-- Nested conditionals -->
<template is="dom-if" if="[[user]]">
<div class="user-section">
<h3>Welcome [[user.name]]!</h3>
<template is="dom-if" if="[[user.isAdmin]]">
<div class="admin-panel">Admin Controls</div>
</template>
</div>
</template>
`;
}
static get properties() {
return {
showContent: Boolean,
showForm: Boolean,
user: Object
};
}
toggleShow() {
this.showContent = !this.showContent;
}
}Element for rendering lists of data with templating and filtering capabilities.
/**
* Renders a template for each item in an array
*/
class DomRepeat extends PolymerElement {
/** Array of items to render */
items: any[];
/** Name for each item in template scope (default: 'item') */
as: string;
/** Name for item index in template scope (default: 'index') */
indexAs: string;
/** Sort function for items */
sort: (a: any, b: any) => number;
/** Filter function for items */
filter: (item: any) => boolean;
/** Space-separated list of properties to observe on items */
observe: string;
/** Delay in microseconds before rendering changes */
delay: number;
/** Number of currently rendered items */
renderedItemCount: number;
/** Force re-render of all items */
render(): void;
/** Get the item associated with a rendered element */
itemForElement(el: Element): any;
/** Get the index of item associated with a rendered element */
indexForElement(el: Element): number;
}Usage Examples:
class ListExample extends PolymerElement {
static get is() { return 'list-example'; }
static get template() {
return html`
<!-- Basic list -->
<template is="dom-repeat" items="[[users]]">
<div class="user-item">
<span>[[item.name]]</span> - <span>[[item.email]]</span>
</div>
</template>
<!-- List with custom item name -->
<template is="dom-repeat" items="[[products]]" as="product">
<div class="product-card">
<h3>[[product.title]]</h3>
<p>$[[product.price]]</p>
</div>
</template>
<!-- List with index -->
<template is="dom-repeat" items="[[items]]" as="item" index-as="i">
<div>[[i]]: [[item]]</div>
</template>
<!-- Filtered and sorted list -->
<template is="dom-repeat" items="[[allUsers]]" filter="isActiveUser" sort="sortByName" observe="name active">
<div class="active-user">[[item.name]] ([[index]])</div>
</template>
<!-- Nested lists -->
<template is="dom-repeat" items="[[categories]]" as="category">
<div class="category">
<h3>[[category.name]]</h3>
<template is="dom-repeat" items="[[category.items]]" as="categoryItem">
<div class="category-item">[[categoryItem.name]]</div>
</template>
</div>
</template>
`;
}
static get properties() {
return {
users: Array,
products: Array,
items: Array,
allUsers: Array,
categories: Array
};
}
isActiveUser(user) {
return user.active;
}
sortByName(a, b) {
return a.name.localeCompare(b.name);
}
}Element that provides data binding capabilities without creating a custom element.
/**
* Provides data binding in templates without defining a custom element
*/
class DomBind extends PolymerElement {
/** Notify path changes up the binding tree */
notifyPath(path: string, value: any): void;
/** Set value at a path and notify */
set(path: string, value: any): void;
/** Get value at a path */
get(path: string): any;
}Usage Examples:
<!-- In HTML, not inside a custom element -->
<dom-bind>
<template>
<h1>[[title]]</h1>
<input value="{{message::input}}">
<p>You typed: [[message]]</p>
<template is="dom-repeat" items="[[items]]">
<div>[[item]]</div>
</template>
</template>
</dom-bind>
<script>
const domBind = document.querySelector('dom-bind');
domBind.title = 'My App';
domBind.message = 'Hello';
domBind.items = ['One', 'Two', 'Three'];
</script>Utility for managing selection state in arrays.
/**
* Mixin for managing selection state in arrays
*/
interface ArraySelectorMixin {
/** Array of items to manage selection for */
items: any[];
/** Whether multiple selections are allowed */
multi: boolean;
/** Currently selected item (single mode) */
selected: any;
/** Array of selected items (multi mode) */
selectedItems: any[];
/** Select an item */
select(item: any): void;
/** Deselect an item */
deselect(item: any): void;
/** Check if item is selected */
isSelected(item: any): boolean;
/** Clear all selections */
clearSelection(): void;
}
/**
* Standalone element for array selection
*/
class ArraySelector extends PolymerElement {
items: any[];
multi: boolean;
selected: any;
selectedItems: any[];
select(item: any): void;
deselect(item: any): void;
isSelected(item: any): boolean;
clearSelection(): void;
}Usage Examples:
class SelectionExample extends PolymerElement {
static get is() { return 'selection-example'; }
static get template() {
return html`
<!-- Array selector element -->
<array-selector id="selector" items="[[items]]" selected="{{selected}}" multi></array-selector>
<!-- Display items with selection state -->
<template is="dom-repeat" items="[[items]]">
<div class$="[[computeItemClass(item, selected.*)]]" on-click="selectItem">
[[item.name]]
</div>
</template>
<!-- Selected items display -->
<div>Selected: [[selected.length]] items</div>
`;
}
static get properties() {
return {
items: Array,
selected: Array
};
}
selectItem(e) {
const item = e.model.item;
this.$.selector.select(item);
}
computeItemClass(item, selectedChangeRecord) {
const isSelected = this.$.selector.isSelected(item);
return isSelected ? 'selected' : '';
}
}Element for registering templates and styles by ID for use in Polymer elements.
/**
* Element for registering templates and styles by ID
*/
class DomModule extends PolymerElement {
/** Module ID for registration */
id: string;
/** Registered template element */
template: HTMLTemplateElement;
/** Array of style elements */
styles: HTMLStyleElement[];
/** Static method to import a module by ID */
static import(id: string, selector?: string): HTMLElement | null;
/** Register this module */
register(id?: string): void;
}Usage Examples:
<!-- Define a template module -->
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
color: var(--my-element-color, blue);
}
</style>
<div>[[message]]</div>
</template>
</dom-module>
<script>
// Use the template in an element
class MyElement extends PolymerElement {
static get is() { return 'my-element'; }
// Template is automatically found from dom-module
}
customElements.define(MyElement.is, MyElement);
</script>Element for defining global styles that can use ShadyCSS features.
/**
* Element for defining document-level styles with ShadyCSS support
*/
class CustomStyle extends HTMLElement {
/** Style modules to include */
include: string;
/** Update the custom style */
updateStyles(): void;
/** Get style information */
getStyle(): CSSStyleSheet;
}Usage Examples:
<!-- Define global custom properties and styles -->
<custom-style>
<style>
html {
--primary-color: #1976d2;
--secondary-color: #388e3c;
--app-background: #fafafa;
}
body {
background-color: var(--app-background);
margin: 0;
font-family: 'Roboto', sans-serif;
}
</style>
</custom-style>
<!-- Include styles from dom-modules -->
<custom-style include="shared-styles app-theme">
<style>
/* Additional styles here */
.app-header {
background-color: var(--primary-color);
}
</style>
</custom-style>interface TemplateInfo {
dynamicFns?: {[property: string]: boolean};
}
interface NodeInfo {
id?: string;
events?: Array<{name: string, value: string}>;
bindings?: Array<Binding>;
}
interface Binding {
kind: 'property' | 'attribute' | 'text';
target: string;
parts: Array<BindingPart>;
}
interface BindingPart {
mode: '{' | '[';
source: string;
signature?: {
methodName: string;
static: boolean;
dynamicFn: boolean;
};
}