Custom properties
As mentioned in the properties & state article, you can still use vanilla properties in the constructor/class. The only difference is such properties will not affect render state in any way, nor will they inherently work with attributes. As you might expect, setting a property using the static properties
method will do nothing if there's an existing accessor.
So what does that mean? Let's look at this example:
constructor() {
super()
this._isOpen = false
}
// Accessors:
set isOpen(value) {
if (value === this.isOpen) return
this._isOpen = value
}
get isOpen() {
return this._isOpen
}
Here, we have the _isOpen
property, which is paired with get
/set
accessors. In this scenario, you control the outcome of your property. It's effectively invisible to Bulba and all its features.
All of the upgrade features are available to you, too:
import { validateType, ... } from "@bulba/element"
attributeChangedCallback(name, oldVal, newVal) {
// Important!
super.attributeChangedCallback(name, oldVal, newVal)
if (name === "is-open" && oldVal !== newVal) {
this.isOpen = newVal
if (typeof this.onAttributeChange === "function") {
this.onAttributeChange("is-open", oldValue, value)
}
}
}
set isOpen(value) {
if (value === this.isOpen) return
// Validate the type is correct
validateType(this, "isOpen", value, "boolean")
// Store the old value before we set the new one
const oldValue = this.isOpen
this._isOpen = value
this.onPropertyChange("isOpen", oldValue, value)
// Optionally reflect the property
this.setAttribute("is-open", String(value))
// Update your view with the new state
// This automatically triggers `onUpdate`
// This is async!
this.requestRender()
}
You should use this strategy sparingly, especially if you have a mixture of upgraded properties and custom properties.