Web Components
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and tools listed are chrome-devtools and lighthouse — both require manual inspection. Misuses like missing observedAttributes, DOM manipulation in constructor, or framework-specific components where vanilla custom elements would suffice are not caught by linters or compilers; they surface only during testing or code review.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes registering a custom element, but the common_mistakes reveal multiple structural issues — super() placement, lifecycle callback misuse, missing observedAttributes, and shadow DOM encapsulation decisions — that collectively require refactoring component class definitions and potentially revisiting design system architecture across multiple component files.
Closest to 'persistent productivity tax' (b5). Web Components apply only to the web context but span the entire frontend. A design system built on them imposes ongoing learning costs around lifecycle callbacks, shadow DOM boundaries, and CSS customisation patterns. Every maintainer must understand the nuances (connectedCallback vs constructor, CSS custom properties for theming), creating a persistent productivity tax across all frontend work streams.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The canonical misconception is that Web Components require no JavaScript, when in fact Custom Elements always need a JS class. Additional traps include DOM manipulation in the constructor (should be in connectedCallback) and missing observedAttributes causing attributeChangedCallback to silently never fire — all documented gotchas that competent developers frequently encounter before learning the correct patterns.
Also Known As
TL;DR
Explanation
Web Components three specs: Custom Elements (define <my-button> as a class extending HTMLElement), Shadow DOM (encapsulated DOM — styles and selectors don't leak in or out), HTML Templates (<template> not rendered until cloned). Custom element lifecycle: connectedCallback (added to DOM), disconnectedCallback (removed), attributeChangedCallback (observed attribute changed). Slots for content projection. Use cases: design systems that work in any framework, micro-frontend boundaries, widgets embedded in third-party pages.
Common Misconception
Why It Matters
Common Mistakes
- Shadow DOM when CSS customisation is needed — use CSS custom properties for theming instead
- Not calling super() first in the constructor — required for custom elements
- DOM manipulation in the constructor — use connectedCallback instead
- Not declaring static observedAttributes — attributeChangedCallback never fires without it
Code Examples
// React-only component — unusable outside React ecosystem:
const Button = ({ label, onClick }) => (
<button className="btn-primary" onClick={onClick}>{label}</button>
);
// Cannot use in Vue, Angular, plain HTML, or future frameworks
// Web Component — works everywhere:
class PrimaryButton extends HTMLElement {
static observedAttributes = ['disabled'];
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>button { background: var(--btn-bg, blue); }</style>
<button part="button"><slot></slot></button>
`;
}
attributeChangedCallback(name, _, value) {
if (name === 'disabled')
this.shadowRoot.querySelector('button').disabled = !!value;
}
}
customElements.define('primary-button', PrimaryButton);
// <primary-button>Click me</primary-button> — works everywhere