Web Components is a set of technologies used in modern web development to create reusable and encapsulated custom HTML elements. It includes Custom Elements, Shadow DOM, HTML Templates, and Slots.
Define custom elements
Define a new HTML element, which can be done through the customElements.define method
class MyElement extends HTMLElement {
constructor() {
super(); // Call the superclass constructor
this.attachShadow({ mode: 'open' }); // Create Shadow Root
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
/* Define the style inside Shadow DOM here */
</style>
<slot>Default content</slot>
`;
}
}
customElements.define('my-element', MyElement);
Encapsulate styles with Shadow DOM
Shadow DOM
allows us to define private CSS styles inside a component, which only affects the elements inside the component and will not leak to the external DOM. In the connectedCallback
above, the Shadow Root
is created and styles are added:
this.shadowRoot.innerHTML = `
<style>
div {
color: blue;
font-size: 24px;
}
</style>
<div><slot></slot></div>
`;
Any text inside <my-element>
will use a blue font and a size of 24px.
Inserting content
Using the <slot>
element, we can allow users to insert content into custom elements, and these contents will be inserted into the corresponding position in the Shadow DOM:
<my-element>
<span>This is the inserted content</span>
</my-element>
In the MyElement class above, the <slot>
element will display the content inserted by the user.
Interactions and events
Custom elements can have their own set of events and interaction logic. For example, you can add an event listener:
class MyElement extends HTMLElement {
// ...
disconnectedCallback() {
// Clean up resources or perform disconnection operations
}
// Add event listeners
buttonClickHandler() {
console.log('Button clicked!');
}
connectedCallback() {
// ...
this.shadowRoot.querySelector('button').addEventListener('click', this.buttonClickHandler.bind(this));
}
}
Reuse and combination
Custom elements can be nested in other custom elements or reused in multiple places to achieve component reuse.
<div>
<my-element>
<button>Click me</button>
</my-element>
<my-element>
<button>Click me again</button>
</my-element>
</div>
Both <my-element>
can respond to click events, and their styles and logic are encapsulated in their respective Shadow DOMs without interfering with each other.
Attributes and Attribute Observation
To make custom elements more flexible and configurable, we can define attributes for them and observe changes in these attributes to responsively update the state or UI inside the component.
Define attributes
In the custom element class, you can declare the list of attributes to be observed through the observedAttributes static property:
static get observedAttributes() {
return ['my-attribute'];
}
Response to attribute changes
Then, respond to attribute changes by overriding the attributeChangedCallback method:
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'my-attribute') {
console.log(`my-attribute changed from ${oldValue} to ${newValue}`);
// Update UI or logic based on attribute changes
}
}
Use attributes
In HTML, you can set these attributes through custom element tags:
<my-element my-attribute="someValue"></my-element>
Style isolation and penetration
Shadow DOM provides style isolation, but sometimes we may want some global styles to also affect the Shadow DOM. You can use the CSS :host pseudo-class to control the style of the custom element itself, while :host-context(selector) allows you to change the style based on the host context.
If you need to affect the style inside the Shadow DOM from the outside, you can use CSS variables (Custom Properties):
/* Define variables in global styles or parent components */
:root {
--my-color: blue;
}
/* Use these variables in the Shadow DOM */
<style>
div {
color: var(--my-color);
}
</style>
Lifecycle methods
In addition to connectedCallback
, disconnectedCallback
, and attributeChangedCallback
, custom elements have other lifecycle methods, such as adoptedCallback
, which is called when the element is moved to a new document.
Performance considerations
Lazy loading and on-demand creation: Ensure that custom elements are created and loaded only when needed to avoid unnecessary performance loss.
Optimize
Shadow DOM
: Minimize the depth and complexity ofShadow DOM
, and avoid overuse of complex CSS selectors, as they may affect rendering performance.
Cross-framework compatibility
Web Components
are designed as native web standards, which means they can work in any browser that supports Web Components
, whether using Angular
, React
or Vue
and other front-end frameworks, can be seamlessly integrated.
Top comments (0)