packages/lit-dev-content/site/tutorials/content/wc-to-lit/07.md
Now all that's missing is the button functionality. This component should allow the user to provide a single up or down vote rating and give visual feedback to the user. In this step you'll do some setup work:
vote property and attribute, like the rating property you added previously.vote attribute.Then in the following step you'll add the event listeners to handle button clicks and set the vote attribute.
Start by adding the following lines:
<template>
<style>
...
:host([vote=up]) .thumb_up {
fill: green;
}
:host([vote=down]) .thumb_down {
fill: red;
}
</style>
</template>
In shadow DOM the :host selector refers to the node or custom element that the shadow root is attached to.
In this case, if the vote attribute is "up" (e.g. <rating-element vote="up">) it will turn the thumb-up button green.
If vote is "down" (e.g. <rating-element vote="down">), then it will turn the thumb-down button red.
Now, implement the logic for this by creating a reflecting property / attribute for vote similar to how you implemented rating. Start with the property setter and getter:
{% switchable-sample %}
export class RatingElement extends HTMLElement {
private _rating = 0;
private _vote: 'up'|'down'|null = null;
...
set vote(newValue) {
const oldValue = this._vote;
if (newValue === oldValue) {
return;
}
if (newValue === 'up') {
if (oldValue === 'down') {
this.rating += 2;
} else {
this.rating += 1;
}
} else if (newValue === 'down') {
if (oldValue === 'up') {
this.rating -= 2;
} else {
this.rating -= 1;
}
}
this._vote = newValue;
this.setAttribute('vote', newValue!);
}
get vote() {
return this._vote;
}
}
export class RatingElement extends HTMLElement {
_vote = null;
...
set vote(newValue) {
const oldValue = this._vote;
if (newValue === oldValue) {
return;
}
if (newValue === 'up') {
if (oldValue === 'down') {
this.rating += 2;
} else {
this.rating += 1;
}
} else if (newValue === 'down') {
if (oldValue === 'up') {
this.rating -= 2;
} else {
this.rating -= 1;
}
}
this._vote = newValue;
this.setAttribute('vote', newValue);
}
get vote() {
return this._vote;
}
}
{% endswitchable-sample %}
Initialize the _vote instance property with null as a class-member property,
and in the setter, check if the new value is different. If so, adjust the
rating accordingly and, importantly, reflect the vote attribute back to the
host with this.setAttribute.
{% aside "warn" %}
It is not recommended to manipulate rating inside the vote setter in this way.
This is not the most efficient way to update rating, but it's the most convenient way for this tutorial.
{% endaside %}
Next, set up the attribute binding for vote:
{% switchable-sample %}
static get observedAttributes() {
return ['rating', 'vote'];
}
attributeChangedCallback(attributeName: string, _oldValue: string, newValue: string) {
if (attributeName === 'rating') {
const newRating = Number(newValue);
this.rating = newRating;
} else if (attributeName === 'vote') {
this.vote = newValue as 'up'|'down';
}
}
static get observedAttributes() {
return ['rating', 'vote'];
}
attributeChangedCallback(attributeName, _oldValue, newValue) {
if (attributeName === 'rating') {
const newRating = Number(newValue);
this.rating = newRating;
} else if (attributeName === 'vote') {
this.vote = newValue;
}
}
{% endswitchable-sample %}
This is the same process you went through with the rating attribute binding:
'vote' to the observedAttributes.vote property in the attributeChangedCallback.Check that this is working by setting the vote attribute to "up" in the
browser dev tools console with $0.setAttribute('vote', 'up').