Skip to main content

Creative Bloq is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission. Learn more

Web components: The ultimate guide

Custom elements can also extend existing ones. It helps to save time by not having to recreate some of the behaviour that's already in the browser. This tutorial shows you how to extend the <time> element to display relative times that machines can understand.

web components

Extend the <time> element to display relative times that machines can understand (Image credit: Matt Crouch)

01. Create the class

Custom built-in elements start life exactly the same as autonomous ones, but instead of extending HTMLElement, they use an existing element as a starting point.

This component uses HTMLTimeElement – the class that <time> elements use. It includes all the behaviour around the datetime attribute, including the format it expects that data to be supplied in.

class RelativeTime extends HTMLTimeElement {}

02. Define the element

Again, much like autonomous custom elements, these also need to be registered with the browser using the define method. One added detail is the third argument, which takes an options object.

For now, this object only has one key, which is used to define exactly which built-in element it customises. It takes the tag name, and will cause an error if it doesn't exist.

customElements.define('relative-time', 
RelativeTime, { extends: "time" });

03. Set the time

As the components set the value of the element in multiple places, it should have a method to call that contains that logic. Inside that method, the component tells the timeago library what that time is and sets its return value as the contents of that element.

Finally, set the title attribute, which allows users to hover their cursor over the text to see the exact time being referenced.

setTime() {
	this.innerHTML = timeago().format(this.
	getAttribute('datetime'));
	this.setAttribute("title", this.
	getAttribute('datetime'));
}

04. Update on connection

The component can use that new method to set the time on the element as soon as it appears on the page. Customised built-in elements cannot have an attached shadow DOM. As there is no other setup required, the component does not need any constructor.

connectedCallback() {
	this.setTime();
}

05. Check attribute changes

At the moment, if the page wanted to update the time programmatically, our component would not react. It does not know it should be watching for changes to the datetime attribute.

By defining observed attributes, the attributeChangedCallback will run each time one of them changes. In this case, the component can run the setTime method again.

static get observedAttributes() {
	return ["datetime"];
}
attributeChangedCallback() {
	this.setTime();
}

06. Add to the page

web components: text saying 'in 1 month'

The final result (Image credit: Matt Crouch)

As this element is an extension of a built-in element, the implementation is a little different. To use our new element, create a <time> tag with an extra is attribute. This should match the name given when defining the component. For browsers that do not support customised built-in elements, they will display the fallback content that is inside instead.

<time is="relative-time" datetime="2019-05-
07T12:00:00+0000">
	12pm on 7th May 2019
</time>

Next page: Tools and frameworks to try