CWCO logo



The WebComponent class allows for very minimal configuration. These are mostly around the shadow root and HTML tag. Everything else must be explicitly set to be taken into consideration.


The tag name is defined by any of the following:

Class name

When you define the class for your component you must use a combination of at least two words distinguished by casing (camel or pascal casing). Your class name is then taken and converted into HTML tags before trying to register it.

The tag name must be a valid custom tag name according to rules defined by web standards.

class FlatList extends WebComponent {}
// becomes flat-list

class TodoItem extends WebComponent {}
// becomes todo-item

class BFSButton extends WebComponent {}
// becomes bfs-button

If you try to access the tagName before you register the component, it will simply return an empty string unless you specified it inside the class.

class FlatList extends WebComponent {}

console.log(FlatList.tagName) // returns ''


console.log(FlatList.tagName) // returns 'flat-list'


You may also use the static tagName inside your class definition. This option is particularly useful if you want to keep your class names simple and a custom tag name to match.

class Button extends WebComponent {
	static tagName = 'bfs-button';

class Todo extends WebComponent {
	static tagName = 'todo-item';

Using this option to define the tag name gives you the advantage of tagName always being there.

class Button extends WebComponent {
	static tagName = 'bfs-button';

console.log(Button.tagName) // returns 'bfs-button'


console.log(Button.tagName) // returns 'bfs-button'


The name of your tag can also be defined when you try to register your tag as a value for the register call.

class List extends WebComponent {}


console.log(List.tagName) // returns 'flat-list'


The mode refers to the shadow root mode.

WebComponent uses the same mode options plus an additional one:

  • open (default): the Element shadowRoot is accessible through Javascript from outside the class.
  • closed: the Element shadowRoot is inaccessible from outside the class via JavaScript.
  • none: the element inner HTML is not placed inside a shadow root. No shadow root is attached to the component.
class TodoItem extends WebComponent {
	static mode = 'closed'; //

You can access the shadow root via root and shadowRoot properties in the instance of the element;

class TodoItem extends WebComponent {
	static mode = 'open';

const todo = new TodoItem();

// accessing the shadow root element


We recommend you use the root property which is specific to CWCO instead of the native shadowRoot. This becomes evident when have mode set to none.

const one = new CompOne(); // mode = open
const two = new CompTwo(); // mode = closed
const three = new CompThree(); // mode = none

one.root // #shadow-root (open)
one.shadowRoot // #shadow-root (open)

two.root // #shadow-root (closed)
two.shadowRoot // #shadow-root (closed)

three.root // <comp-three></comp-three>
three.shadowRoot // null

Accessing the root of the component is important if you want to query or read the elements inside the component.


The delegateFocus options controls how the internal focus propagates to the host tag. It can be very useful to apply focus to the component tag when some internal element receives focus.

In the example below, whenever the input field receives focus, the entire component tag will have the browser outline style applied to it. Notice that the outline style is removed from the field to avoid double outline.

class SearchField extends WebComponent {
	static delegateFocus = true;
	get template() {
		return `
				<input type="search" style="outline: none">

This is nice because the whole component is seen as one.

Traditionally you would do this:

class MyButton extends HTMLElement {
	constructor() {
		this.attachShadow({mode: 'closed', delegatesFocus: true});

customElements.define('my-button', MyButton)

With CWCO you can do this:

class MyButton extends WebComponent {
	static mode = 'closed';
	static delegatesFocus = true;