Skip to content

HTML Components

Greg Bowler edited this page Apr 26, 2024 · 10 revisions

All parts of a web application's user interface are made of HTML. Complex user interfaces like calendars or rich text editors can be made of many nested elements, which would be very difficult to maintain directly within the page. With HTML Components, it's possible to maintain nested HTML structures in separate HTML files and import them into the document by name, using custom HTML tags <like-this>. This has the added benefit of being able to reuse components of HTML across different pages (or multiple times within the same page).

Example HTML page:

<p>Pick a date from the calendar</p>

<form method="post">
	<calendar-control />
	<button name="do" value="set-date">Pick selected date</button>
</form>

The calendar-control component can be stored in a separate file called calendar-control.html, in a component directory.

_component/calendar-control.html

<form method="post">
	<select name="calendar-year" data-bind:value="selectedYear">
		<option data-list data-bind:text="year">0000</option>
	</select>
	<select name="calendar-month" data-bind:value="selectedMonth">
		<option data-list data-bind:text="monthName" data-bind:value="month">Month</option>
	</select>

	<ol>
		<li data-list>
			<label>
				<input type="radio" name="selectedDay" data-bind:value="day" />
				<span data-bind:text="day">0</span>
			</label>
		</li>
	</ol>
</form>

Naming convention

A component can be named anything, a long as it contains a hyphen. This is a rule set by the HTML Living Standard to avoid custom element names clashing with new functionality introduced in future HTML versions - official HTML elements will never contain hyphens.

It's common to use a namespace-like naming convention with custom elements. For example, in an application that has heavy calendar functionality, all calendar components might have names that begin with cal-, which will aid the understanding of where each component lives within the application.

Storing components in subdirectories

A directory path is provided to PartialContent objects when they are constructed, indicating where component HTML files are stored. In WebEngine applications, this path defaults to page/_component.

When there are many components within an application it may be easier to manage if components were stored in subdirectories of the component directory. For example, assuming the component directory is page/_component, a component can be stored in page/_component/calendar/date-picker.html and referenced in HTML like this:

<date-picker src="calendar" />

The src attribute is used to load from any subdirectory of the base component directory. It can be nested as much as necessary.

With components being able to be stored in separate directories, it's possible to have components with the same name but loaded from different directories.

<!-- expand from calendar/date-picker.html -->
<date-picker src="calendar" />

<!-- expand from christmas/date-picker.html -->
<date-picker src="christmas" />

Recursive components

It's possible to put components within any HTML file, including within other components' HTML. There is no limit to the number of layers components will expand through.

PHP functionality of components

When binding data to the document as a whole, the DocumentBinder class is usually used, which has access to the whole document. However, since HTML components allow you to isolate a sub-tree of the document within a custom HTML tag, it is useful to be able to bind to just the component itself, without accidentally leaking data elsewhere into the document.

This can be achieved using the ComponentBinder class, which has identical functionality to the DocumentBinder apart from it takes a single element as an extra dependency.

The ComponentBinder can be used in exactly the same manner as with the DocumentBinder, and has no additional functionality. Its only purpose is to automatically constrain the binding process to a given context element.

Both the ComponentBinder and the DocumentBinder extend from the abstract Binder base class. This is so that in WebEngine applications, when adding type hints in a go or do function, you will automatically be provided with the appropriate type of Binder, depending on whether you are in the context of page's PHP logic file, or a component's PHP logic file.

// TODO: Link to the WebEngine documentation, when it's available.


Next, learn how to template pages using Partial HTML.