Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Register every attribute a custom element reads in observedAttributes
A Web Component's attributeChangedCallback only fires for attributes declared in observedAttributes — new flags read in render logic must be added there too.
Bad example
| 1 | class WidgetElement extends HTMLElement { |
| 2 | static get observedAttributes() { |
| 3 | return ['show-count']; |
| 4 | } |
| 5 |
|
| 6 | render() { |
| 7 | const showCount = this.hasAttribute('show-count'); |
| 8 | const showJumpPages = this.hasAttribute('show-jump-pages'); // read but not observed |
| 9 | // ... |
| 10 | } |
| 11 | } |
Explanation (EN)
`show-jump-pages` is read during render but missing from `observedAttributes`. Calling `element.setAttribute('show-jump-pages', 'true')` later does nothing visible unless `show-count` also changes in the same update.
Objašnjenje (HR)
`show-jump-pages` se čita tijekom rendera, ali nije u `observedAttributes`. Kasniji poziv `element.setAttribute('show-jump-pages', 'true')` ne radi ništa vidljivo, osim ako se `show-count` ne promijeni u istom updateu.
Good example
| 1 | class WidgetElement extends HTMLElement { |
| 2 | static get observedAttributes() { |
| 3 | return ['show-count', 'show-jump-pages']; |
| 4 | } |
| 5 |
|
| 6 | render() { |
| 7 | const showCount = this.hasAttribute('show-count'); |
| 8 | const showJumpPages = this.hasAttribute('show-jump-pages'); |
| 9 | // ... |
| 10 | } |
| 11 | } |
Explanation (EN)
Every attribute the render logic reads is listed in `observedAttributes`, so `attributeChangedCallback` fires reliably whenever any one of them changes, independent of the others.
Objašnjenje (HR)
Svaki atribut koji render logika čita naveden je u `observedAttributes`, pa se `attributeChangedCallback` pouzdano okida kad god se bilo koji od njih promijeni, neovisno o ostalima.
Notes (EN)
This is easy to miss because the component still works correctly on initial mount (attributes present at construction time are always read); the bug only shows up when a consumer updates the attribute dynamically after the element already exists.
Bilješke (HR)
Ovo je lako promašiti jer komponenta radi ispravno pri inicijalnom mountanju (atributi prisutni pri konstrukciji uvijek se pročitaju); bug se pojavi tek kad potrošač dinamički promijeni atribut nakon što element već postoji.
Exceptions / Tradeoffs (EN)
Deliberately omitting an attribute from observedAttributes because it is genuinely meant to be set-once (never updated post-mount) is fine, but should be a conscious, documented decision, not an oversight.
Iznimke / Tradeoffi (HR)
Namjerno izostavljanje atributa iz observedAttributes jer je zamišljen kao 'postavi jednom' (nikad se ne mijenja nakon mounta) je u redu, ali treba biti svjesna, dokumentirana odluka, a ne previd.