Prop Access
Ang props property ng WebComponent interface ay ibinibigay para sa madaling read/write access sa camelCase counterpart ng kahit anong observed attribute.
class HelloWorld extends WebComponent { static props = { myProp: 'World', } get template() { return html` <h1>Hello ${this.props.myProp}</h1> ` }}Ang pag-assign ng value sa props.camelCase counterpart ng isang observed attribute ay magpapagana ng “attribute change” hook.
Halimbawa, ang pag-assign ng value nang ganito:
this.props.myName = 'hello'…ay katulad ng pagtawag sa sumusunod:
this.setAttribute('my-name','hello');Kaya, sasabihin nito sa browser na kailangan ng UI ng render kung ang attribute ay isa sa mga observed attribute ng component na malinaw nating ibinigay gamit ang static props;
Opt-in na typed props sa TypeScript
Seksyong pinamagatang “Opt-in na typed props sa TypeScript”Tingnan ito nang live: Compile-time prop types demo ↗ at Typed props demo ↗
Bilang default, ang this.props ay isang permissive na { [name: string]: any } map. Sa TypeScript, makakakuha ka ng compile-time types sa mga na-declare mong props. I-declare ang shape bilang isang named type, ipasa ito bilang class type argument, at i-annotate ang static props gamit ito sa initialization:
type CozyButtonProps = { variant: 'primary' | 'ghost' disabled: boolean}
class CozyButton extends WebComponent<CozyButtonProps> { static props: CozyButtonProps = { variant: 'primary', disabled: false, }
get template() { this.props.variant // 'primary' | 'ghost' this.props.disabled // boolean this.props.notAProp // ❌ compile error: not declared
this.props.disabled = 'yes' // ❌ compile error: string is not boolean this.props.variant = 'plaid' // ❌ compile error: not in the union return html`<button class=${this.props.variant}></button>` }}Ang annotation na ito ay nag-a-apply ng type-check sa mga susunod na assignment habang ang mga default mismo ay sinusuri laban sa type, kaya ang isang missing key o isang default na wala sa union ay isa ring compile error.
Boolean props
Seksyong pinamagatang “Boolean props”Ang mga boolean prop ay sumusunod sa HTML boolean-attribute convention, katulad mismo ng native
na disabled at required: ang presence ay nangangahulugang true, ang absence ay nangangahulugang false.
Tingnan ito nang live: Boolean props demo ↗
class FlagBox extends WebComponent { static props = { flag: false }}<!-- props.flag === false --><flag-box></flag-box>
<!-- props.flag === true --><flag-box flag></flag-box>
<!-- props.flag === true --><flag-box flag=""></flag-box>Ang reflection ay gumagana sa parehong paraan sa kabaligtaran. Ang true ay nagse-set ng bare attribute,
tinatanggal ito nang tuluyan ng false:
el.props.flag = true // <flag-box flag>el.props.flag = false // <flag-box>Dahil ang false ay isang absent na attribute sa halip na flag="false", kapwa
kumikilos ang API mismo ng platform at ang CSS presence selectors ayon sa inaasahan mo:
el.toggleAttribute('flag', true) // prop syncs, component re-renders:host([flag]) { /* matches only when the prop is actually true */}Ang mga enumerated attribute tulad ng contenteditable at ang mga aria-* attribute ay ang
eksepsyon. Mga tunay na string ang mga ito kung saan makabuluhan ang "false", kaya i-declare
ang mga ito bilang string props sa halip na boolean. Nagsi-serialize ang mga string nang literal at
hindi kailanman tinatanggal, kaya walang kailangang espesyal sa runtime; sa TypeScript,
paliitin ang mga ito sa mga value na tinatanggap mo sa iyong
props type:
type ToggleProps = { ariaChecked: 'true' | 'false'}Custom na attribute conversion
Seksyong pinamagatang “Custom na attribute conversion”Tingnan ito nang live: Custom attribute converters demo ↗
Sinasaklaw ng mga panuntunan sa itaas ang karaniwang mga kaso. Kapag kailangan ng isang prop ng sarili nitong
serialization (isang Date, isang delimited list, isang enumerated attribute kung saan
makabuluhan ang "false") i-override ang toAttribute at fromAttribute, at
i-delegate ang lahat ng iba pa sa super:
class EventCard extends WebComponent { static props = { when: new Date(0), title: '' }
toAttribute(name, value) { if (name === 'when') return value.toISOString().slice(0, 10) return super.toAttribute(name, value) }
fromAttribute(name, value) { if (name === 'when') return new Date(`${value}T00:00:00Z`) return super.fromAttribute(name, value) }}<!-- props.when is a Date --><event-card when="2026-07-20"></event-card>Kapwa kumukuha ang mga ito ng camelCase prop key, na tumutugma sa iyong static props declaration
at sa property ng onChanges, hindi ang kebab-case attribute name.
Ang pagbabalik ng toAttribute ng null ay nagtatanggal ng attribute. Ganito rin mismo nagiging
absent attribute ang isang false na boolean, at magagamit ito para sa kahit anong prop:
toAttribute(name, value) { // an empty string means "no attribute at all" for this prop return value === '' ? null : super.toAttribute(name, value)}Ang conversion ay tinatawag lamang sa mga pagbabago sa attribute
Seksyong pinamagatang “Ang conversion ay tinatawag lamang sa mga pagbabago sa attribute”Kapag nag-a-assign ng value sa isang prop, ang wcb ay hindi sumusuri at nagpa-parse pabalik sa
attribute sa pamamagitan ng fromAttribute. Ang prop na in-assign mo ay siya nang
source of truth at ang text form na attribute ay maaaring mas hindi eksaktong
representasyon. Sa halimbawa sa itaas, pinapanatili ng props.when ang buo nitong
timestamp kahit na ang attribute ay may dalang petsa lamang. Nagpapagana pa rin ang render() at
onChanges nang normal. Ang fromAttribute conversion ay tinatawag lamang
para sa mga attribute na isinulat mula sa labas ng component sa pamamagitan ng markup, setAttribute,
o toggleAttribute.
Paghawak sa mga non-serializable na data type
Seksyong pinamagatang “Paghawak sa mga non-serializable na data type”Ina-round-trip ng default na converters ang mga prop value sa pamamagitan ng JSON, na nagpapanumbalik
sa mga numero, boolean, at plain objects/arrays nang eksakto. Ang mga type na hindi kayang katawanin ng JSON ay hindi nabubuhay sa
biyahe: ang isang Date ay bumabalik bilang plain string, at ang isang
Map o Set ay bumabagsak sa "{}".
Ang mga ganitong type ay first-class na props pa rin. Maaari kang mag-declare ng totoong default ng type na iyon (tingnan ang babala sa itaas) at i-override ang converters. Hinahawakan ito ng halimbawang EventCard sa itaas sa pamamagitan ng paggamit ng custom na conversion logic para sa Date prop nito.
Ang isa pang paraan para gawin ito ay ang paggamit sa halip ng library na ginawa para sa trabahong ito.
Maaari mong piliing gumamit ng serializer tulad ng devalue bilang dependency ng iyong component, na kayang mag-serialize at mag-parse ng Map, Set, Date, RegExp, BigInt, undefined, at maging cyclic references. Isang
generic na pares ng overrides ang sumasaklaw na sa bawat structured prop.
Narito ang EventCard na muling isinulat gamit ito, na may karagdagang prop na tags na uri ng Set:
import { parse, stringify } from 'devalue'
class EventCard extends WebComponent { static props = { when: new Date(0), tags: new Set(), title: '', }
toAttribute(name, value) { // handles `when` and `tags` if (value instanceof Object) return stringify(value) return super.toAttribute(name, value) }
fromAttribute(name, value) { if (this.constructor.props[name] instanceof Object) return parse(value) return super.fromAttribute(name, value) }}Ang dalawang guard ay sadyang asymmetric: nakikita ng toAttribute ang live value,
ngunit ang fromAttribute ay lagi na lang nakakakita ng string, kaya kinukonsulta nito ang na-declare
na default (gamit ang this.constructor.props) para malaman kung ang attribute ay
devalue-encoded. Naliligtaan ng title ang dalawang guard at nagre-reflect bilang plain string,
eksakto tulad ng dati.
Ang encoded na attribute ay hindi kasing-readable ng isang bespoke na when="2026-07-20",
ngunit plain text pa rin ito:
<!-- props.when is a real Date, props.tags a real Set --><event-card when='[["Date","2026-07-20T09:30:00.000Z"]]' tags='[["Set",1,2],"alpha","bravo"]'></event-card>Sinasaklaw ng converters ang anumang value na may makatwirang textual form: bespoke tulad ng
ISO date, o generic tulad ng encoding ng devalue. Ang value na walang textual form
(isang function, isang element reference, isang live handle tulad ng
AbortController) ay hindi problema sa converter: kahit ang devalue ay tumatanggi rito
(Cannot stringify a function), at hindi ito dapat nasa static props sa
umpisa pa lang. Sa halip, panatilihin itong isang plain class property. Tingnan
ang Unobserved properties sa ibaba. Nagbabala ang wcb nang isang beses bawat
class kapag ang isang na-declare na default ay isang function o symbol para sa eksaktong dahilang ito.
Mga Unobserved property
Seksyong pinamagatang “Mga Unobserved property”Lahat ng na-declare sa static props ay observed at reflected: ang bawat key ay nakakakuha ng
attribute, ang mga write ay nagpapagana ng render() at onChanges(), at lumalabas ang default
sa DOM sa unang connect. Iyan ang tamang kontrata para sa public, DOM-facing na API
ng isang component, at hindi kailangan para sa internal state.
Para sa state na hindi dapat nasa DOM, gumamit ng plain class property. Ang isang
WebComponent ay isa pa ring class na nagpapalawig sa HTMLElement, kaya ang mga ordinaryong
property ay gumagana nang eksakto tulad ng sa kahit anong element at hindi nakikita ng props
machinery (walang attribute, walang observation, walang awtomatikong render):
class DataTable extends WebComponent { static props = { compact: false } // public API: <data-table compact>
rows = [] // internal state, never becomes an attribute #controller = new AbortController() // non-serializable values are fine here
async onInit() { const res = await fetch('/rows', { signal: this.#controller.signal }) this.rows = await res.json() this.render() // unobserved changes render when you say so }
onDestroy() { this.#controller.abort() }}Dahil walang bumabantay sa plain property, tawagin mismo ang
this.render() kapag dapat mag-update ng view ang pagbabago sa isa.
Ang rule of thumb: ang static props ay para sa mga value na ise-set ng consumer mula sa markup o
kung saan mag-i-istilo laban sa attribute selectors; ang class property (public o
#private) ay para sa lahat ng iba pa: malaking data, mga function, at mga handle tulad ng
timers o AbortControllers na hindi kailanman makaka-round-trip sa attribute
kung tutuusin. Kung napansin mong iniisip mo, “ayaw kong lumabas ito bilang
attribute”, iyan ang senyales na dapat itong maging class property, hindi prop.
Mga Alternatibo
Seksyong pinamagatang “Mga Alternatibo”Ang mga kasalukuyang alternatibo ay ang paggamit sa ibinibigay na ng HTMLElement out-of-the-box, na kung saan:
HTMLElement.datasetpara sa mga attribute na maydata-*prefix. Magbasa pa tungkol dito sa MDN.- Mga method para sa pagbasa/pagsulat ng attribute values:
setAttribute(...)atgetAttribute(...); tandaan na ang pamamahala sa attribute names bilang strings ay maaaring maging mahirap habang lumalaki ang code.