CWCO logo

v1.7.6

Template

The web component template is a way for you to communicate to WebComponent what the inner HTML of your component looks like.

Other libraries simply take your HTML or JSX and recalculate things when data are changed.

cwco templates works differently than other libraries. It will only be read once when adding the component to the DOM for the first time. The template is simply a static data source.

Define Template

All you need to define your component template is set a getter for template where you return the HTML string representing the inner part of your component

class TodoItem extends WebComponent {
	get template() {
		return `
			<div class="todo-item">
				<h3>My Todo</h3>
				<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem debitis vitae voluptatibus?</p>
				<p><strong>Status</strong> In Progress</p>
			</div>
		`;
	}
}

It is important to keep template readonly with the getter. You may see errors if you don't do so, especially if you use CWCO in a typescript project.

Template ID

You may also use HTML template tag to define the template of your component and all you have to do is tell the component about the template id.

<!-- documentation.html -->
<template id="todo-item-template">
	<div class="todo-item">
		<h3>My Todo</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem debitis vitae voluptatibus?</p>
		<p><strong>Status</strong> In Progress</p>
	</div>
</template>
class TodoItem extends WebComponent {
	templateId = "todo-item-template";
}

Data Binding

You can use curly braces to bind data to your templates. Inside, you can refer to properties from which you want the value from or add logic that produces value to be added to the element.

class TodoItem extends WebComponent {
	title = 'untitled';
	description = '';
	status = 'in-progress';
	
	get template() {
		return `
			<div class="todo-item">
				<h3>{title}</h3>
				<p>{description}</p>
				<p><strong>Status</strong> {status}</p>
			</div>
		`
	}
}

cwco tracks these data references and know when and where to update the DOM when there is a data change. You don't have to do anything to update the DOM once there is a data change.

Escaping curly braces

There are cases where you want to add a curly brace to your template but don't mean it as data binding. For example, in a regex for the input pattern attribute:

<input type="text" pattern="{0,9}">

Just leaving it like that will throw an error because it will assume you want to execute what's inside the curly braces which is an invalid Javascript expression.

To solve this you can wrap it in single quotes and again wrap that in curly braces. What this does is execute what's inside the curly braces resulting in a string matching the regex pattern you want.

<input type="text" pattern="{'{0,9}'}">

Data Logic

Inside the curly brace you can put javascript logic that gets executed and result is added to the template.

class TodoItem extends WebComponent {
	title = 'untitled';
	description = '';
	status = 'in-progress';
	
	get template() {
		return `
			<div class="todo-item {status === 'done' ? 'completed' : 'pending'}">
				<h3>{title}</h3>
				<p>{description}</p>
				<p><strong>Status</strong> {status === 'done' ? 'Done' : 'In Progress'}</p>
			</div>
		`;
	}
}

CWCO evaluates strings on the fly. This can become a concern if you have strict CSP configurations that does not allow unsafe-eval.

If working with CWCO, you must allow unsafe-eval CSP. We try our best to minimize the risks in evaluations by executing strings in contextualized scope your component is in.

the "this" keyword

There will be situations that you must use the this keyword in order to put data in the template.

Any explicit public properties declared or observed attributes defined can be referenced in the template without the need to use the this keyword.

class SampleComp extends WebComponent {
	static observedAttributes = ['sample', 'style', 'class', 'data-x'];
	numb = 12;
	#priv = 'yes'
	
	get template() {
		return '{this.#priv}<strong class="{this.className}" style="{this.style.cssText}" data-x="{this.dataset.x}">{numb} {sample}</strong>'
	}
}

If the property is something that exists in the HTMLElement or any of its ancestors, you must explicitly reach them using the this keyword.

The same is true for any private properties and getters.

Javascript Template Literal

There is a huge difference between the Javascript template literal curly braces and cwco template data binding curly braces.

You can use template literal to generate the template string for WebComponent but its notation is not used in calculating the DOM for the element. Also, remember that the template is only calculated once so if you add logic to update template on data change in the ${...} notation, it will not be executed on update.

Inside the template string, ${...} is different than {...}.

Taking in consideration the above TodoItem class...

This...

`<div class="todo-item ${status === 'done' ? 'completed' : 'pending'}">
	<h3>${title}</h3>
	<p>${description}</p>
	<p><strong>Status</strong> ${status === 'done' ? 'Done' : 'In Progress'}</p>
</div>`

...becomes...

`<div class="todo-item pending">
	<h3>untitled</h3>
	<p></p>
	<p><strong>Status</strong> In Progress</p>
</div>`

...which tells WebComponent nothing about where to update on data change.

It is important for the template to contain the curly braces to mark the placeholders to put the data into.

slots

Using HTML slot tag will make templates more flexible and dynamic. It is the final detail when it comes to template.

With WebComponent slots are even more powerful and allows for something no other library can do.

You can create your app root tag where the template is a single slot tag which means anything you put inside the app will just get picked up and rendered allowing you to do data and event binding, use directives and more.

const {WebComponent} = window;

class SampleApp extends WebComponent {
	static initialContext = {
		site: {
			title: 'BFS Web Component App',
			description: 'The only framework you need to build your Web Application'
		}
	};
	
	get template() {
		return '<slot></slot>';
	}
}

With this powerful app tag you can compose your entire application right in your HTML file unlike other frameworks that require you to put the entire app inside the app component body.

<!-- documentation.html -->

<test-app>
	<h1>{site.title}</h1>
	<p>{site.description}</p>
	<section repeat="['Welcome', 'About Us', 'Contact']">
		<h2>{$item}</h2>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid at distinctio
		   eos illo laudantium obcaecati odio quos rerum voluptate voluptatem. Quis!</p>
	</section>
	<footer>
		<p>Copyright &copy; BDS Web Component</p>
	</footer>
</test-app>

This means that you can server side render your application as much as possible and ship only the components that will handle the non-static part of your website.