- We can create custom HTML elements, described by our class, with its own methods and properties, events and so on.
Once a custom element is defined, we can use it on par with built-in HTML elements.
Internal vs. external styles
- That’s great, as HTML dictionary is rich, but not infinite.
- There are no
, , … Just think of any other tag we might need.
- We can define them with a special class, and then use as if they were always a part of HTML.
Customized built-in elements
- There are two kinds of custom elements:.
- Autonomous custom elements – “all-new” elements, extending the abstract HTMLElement class.
- Customized built-in elements – extending built-in elements, like a customized button, based on HTMLButtonElement etc.
Creating an element which disables the ability to attach a shadow root
- First we’ll cover autonomous elements, and then move to customized built-in ones.
- To create a custom element, we need to tell the browser several details about it: how to show it, what to do when the element is added or removed to page, etc.
- That’s done by making a class with special methods.
- That’s easy, as there are only few methods, and all of them are optional.
- Here’s a sketch with the full list:.
- After that, we need to register the element:.
- Now for any HTML elements with tag
, an instance of MyElement is created, and the aforementioned methods are called.
Autonomous custom elements
- Custom element name must have a hyphen -, e.g.
- my-element and super-button are valid names, but myelement is not.
- That’s to ensure that there are no name conflicts between built-in and custom HTML elements.
- For example, there already exists
- But it doesn’t do any formatting by itself.
- Let’s create
element that displays the time in a nice, language-aware format:.
- The class has only one method connectedCallback() – the browser calls it when
element is added to page (or when HTML parser detects it), and it uses the built-in Intl.DateTimeFormat data formatter, well-supported across the browsers, to show a nicely formatted time.
- We need to register our new element by customElements.define(tag, class).
- And then we can use it everywhere.
- If the browser encounters any
elements before customElements.define, that’s not an error.
- But the element is yet unknown, just like any non-standard tag.
- Such “undefined” elements can be styled with CSS selector :not(:defined).
- When customElement.define is called, they are “upgraded”: a new instance of TimeFormattedis created for each, and connectedCallback is called.
- They become :defined.
- To get the information about custom elements, there are methods:.
Upgrading Custom Elements
- customElements.get(name) – returns the class for a custom element with the given name,.
- customElements.whenDefined(name) – returns a promise that resolves (without value) when a custom element with the given name becomes defined.
- Rendering in connectedCallback, not in constructor.
- In the example above, element content is rendered (created) in connectedCallback.
Autonomous custom element
- Why not in the constructor?
- The reason is simple: when constructor is called, it’s yet too early.
- The element is created, but the browser did not yet process/assign attributes at this stage: calls to getAttribute would return null.
- So we can’t really render there.
Chrome for Android
- Besides, if you think about it, that’s better performance-wise – to delay the work until it’s really needed.
Firefox for Android
- The connectedCallback triggers when the element is added to the document.
UC Browser for Android
- Not just appended to another element as a child, but actually becomes a part of the page.
- So we can build detached DOM, create elements and prepare them for later use.
- They will only be actually rendered when they make it into the page.
- In the current implementation of
, after the element is rendered, further attribute changes don’t have any effect.
- That’s strange for an HTML element.
- Usually, when we change an attribute, like a.href, we expect the change to be immediately visible.
- So let’s fix this.
- We can observe attributes by providing their list in observedAttributes() static getter.
- IE Web Platform Status and Roadmap: Custom Elements
- Firefox tracking bug: Implement Custom Elements (from Web Components)
- Google Developers - Custom elements v1: reusable web components
- customElements.define polyfill
- WebKit Blog: Introducing Custom Elements