Copyright © 2018 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
Web components allow you to create encapsulated custom elements on the web platform, but how can you make sure that those elements actually follow common guidelines in such a way that useful elements fit in well with the rest of the platform? The TAG believes this is important so that users don’t feel like they are dealing with mismatched APIs and also a requirement if any of these elements were to end up in the HTML standard.
This document has been produced by the W3C Technical Architecture Group (TAG).
Please raise issues on our issue list, alternatively, you can send comments on this finding to the publicly archived TAG mailing list www-tag@w3.org (archive).
The web platform is not known for being 100% consistent, but there are definitely some recognizable patterns across the platform, like with regard to naming. Try to stay consistent with what is already used, like if other elements uses “selected” as an attribute for the same behavior, there is no reason to start using something else (say, “chosen” or “marked”).
In order to answer that, we need to look how native elements work, and what defines them:
Elements don’t throw errors when used declaratively. Native elements don’t throw errors during construction or using regular DOM interactions.
For example, they don’t strictly enforce their content model. You can easily add a
div
element inside animg
element even if that means it won’t render or behave properly, it should never throw.
Elements are self-contained. Elements come as part of the web platform and thus will work without requiring any other libraries.
Use events to pass data to the outside world. All custom elements inherit from EventTarget, and thus events can be used to pass data along, but please follow the guidelines in the DOM Living Standard §2.11. See also the TAG’s guidance on event design.
Use attributes to receive non-complex data. Elements are configured declaratively as much as possible, which allows them to be used declaratively, as well as work great with template bindings.
There are a few things to keep in mind though
<my-element selected=""></my-element>
instead of
<my-element selected="true"></my-element>
.bgcolor
.
Instead use Custom Properties
or CSS Shadow Parts.Interactive elements are focusable, and can be interacted with using a keyboard in addition to mouse/touch. Generally, make sure that elements are accessible.
Elements can be instantiated without being part of the document. Element can be created from scripts etc before inserted into the document, so don’t assume that document APIs like parentNode will be available before connectedCallback.
Elements should only have basic styling. Native elements are implementable by multiple browsers on multiple platforms, so they have only generic styling out of the box. Theming of the element might be desired, but should be separated out from the essential style of the element (and made extensible). Create the simplest style possible—at least as basic, if not more, than existing standard elements. We can call this functional styling in contrast to “theme” like styling.
It would not be appropriate to encode a specific UI styling, like Material Design (Google) or Cupertino (Apple), into the element.
It is appropriate to create styling hooks to allow elements to be themed to match popular styles, like Material and Cupertino.
Apart from following the properties of native elements, there are a lot of other ways to make an element fit well with the web platform.
Don’t enforce unnecessary child/parent relationships. Even though your element is intended to be used in conjunction with another element, attempt to make it works as child of any other element, if that makes sense.
Avoid using callbacks. Refer to TAGs guidance on promises.
Harmonize declarative (HTML) and imperative (JavaScript) APIs.
Attributes (HTML) form (part of) your declarative API; your prototype
defines your imperative (JavaScript) API. Try to keep the analogous
parts linked whenever possible so a user can modify either with the
same effect. (eg. <my-element opened="">
or this.opened = true
).
Elements can store values set via attributes or imperative APIs in the attribute itself, or in the JavaScript property or elsewhere, but should be consistent. Come up with a plan for state management and stick to it consistently.
Custom elements have the requirement that they need to contain a hyphen (-) in their name. That is important, as it means that we can standardize elements by never allowing a hyphen - in that way, there will be no name clash.
Thanks to Alex Russell, Sangwhan Moon, David Baron, Domenic Denicola add Travis Leithead for their contributions to this document.