Check out a free preview of the full Web Components course
The "Basic Counter" Lesson is part of the full, Web Components course featured in this preview video. Here's what you'd learn in this lesson:
Dave creates a my-counter component that has increment and decrement buttons for changing the value. Component properties can either be exposed as an attribute in HTML or be localized state within the component.
Transcript from the "Basic Counter" Lesson
[00:00:00]
>> For the next hour or so, we're gonna kinda go through an author web components, which is kind of exciting. We haven't really done that yet in the web components course, but now we're finally here. Now, we understand all the principles and have had some challenges [LAUGH] along the way, we are excited to code.
[00:00:20]
I have three basic examples in the guidebook. I think we maybe have time for two if we wanna get out of here and so. And then the big one, the basic counter example, right? So just how do you do an increment button? Maybe we can add some styles to it, make it kind of cool, maybe we'll start there.
[00:00:40]
I have the custom alert example, where that custom alert I built in, and then I can close it, and then it hides and disappears. We could also do that one, but I think we'll just do the counter thing, that's probably the easiest way to get through it. And then kind of the big one, right?
[00:00:54]
Let's build an app that looks for local breweries, and we can see if we visited them and check them off as we go. Maybe something like that, something pretty useful, utilitarian. [LAUGH] And then kind of annoying maybe get into the more like what does an actual app whole design system, whole everything kind of feel like?
[00:01:13]
How do we do that? And maybe the easiest way to get going and get started some. So we'll kind of start with the basic counter, and you can maybe, at this point, probably yell it at me. [LAUGH] But so I have some cheaters here. So here, we need to start with a basic.
[00:01:38]
We want my-counter, right? And we want it to show up here, let me see, nothing's defined, okay, here we go. I'm just gonna call it my-counter just so we know it for later, and then we're gonna type garbage in here. So we know when the shadow DOM shows up.
[00:01:58]
[LAUGH] We did our job right, right? So I think the first thing we're gonna see, let's see here, nothing's happening, is that correct? That seems like it should render at least something. Yeah, okay, cool, I need to figure out what's going on. Maybe I'll just make sure that that's also, okay, cool, all right.
[00:02:19]
CodePen thinks I'm a hacker, okay, great, [LAUGH] we're good. Okay, we're back, CodePen, we're good. CodePen might be upset with how many changes I've made today. Great, here we go. All right, so the outline, right, class. We do classes, but if we wanted to be cool to our friends who might wanna use this array, we could do that.
[00:02:46]
My-counter extends, and do we want to do the lit one? Let's just do lit, cuz I'm not really a framework's guy, I'm not really a just use a library guy. But library solve a lot problems, and I think we're gonna [LAUGH] in this circumstance for a five to seven kilobyte penalty.
[00:03:09]
I think it's a good trade-off just for learning. So MyCharacter is going to extend LitElement, but of course, we need import, we're going to go get LitElement, right? Element, and then we know we want the HTML thing, and we might as well just grab the CSS while we're here.
[00:03:33]
From lit, right, and then it's gonna say, CodePen has this nice feature, it says, I don't know what you're talking about. So we're gonna go get it from Skypack. Great, we have it. And then the last thing, we need to do customElements, plural, define my-counter. And it's going to point to the MyCounter class.
[00:03:57]
Easy enough, we're good here. Okay, we're gonna have some static properties, right? We have what? What properties would our counter need to keep track of?
>> Count, yeah.
>> Count, okay, great. Yeah, it needs to keep track of a count, right? And so, and then I'll circle back to that, but that's what it's gonna need, it needs a count, right?
[00:04:26]
We know we needed the constructor, which is not my favorite part, but that's just life in class based programming. [LAUGH] So we're gonna call this super, and then we're probably going to initialize this count, right, to 0. So this will be the section where we want to kinda set it.
[00:04:49]
There may be a way to set it up here, I don't know it offhand, so I just set it down there. And then because we're in Lit, we're gonna do a render function, right? And then what does our render function do? Return html, right? And then it's gonna have the button, plus or minus, we'll put the -1 first.
[00:05:15]
We'll return this count, and then we'll have a button that it makes it go up, okay, into that. The pieces are in there, it's not interactive, nothing happens here, but that's actually really easy to do. We have a question, yeah.
>> Yeah, I don't wanna get off track on framework stuff, but why is count an object in the properties?
[00:05:45]
>> Good question, [LAUGH] I think you can maybe just make it count, but it didn't yell at me, but I don't know if it's gonna do anything yet. One reason you do that, and what I was gonna test here was trying to get into the increment and decrement.
[00:06:09]
And so one thing you do here to say it's a reactive property is this state true? And so you're basically saying, this is a piece of state, so let's keep track of it like a piece of state. So is that-
>> It's hard configuration, then this is a property on this class.
[00:06:29]
>> Totally, and then you can actually pass a type, it doesn't do anything here. It doesn't actually do type checking, although, in theory, we're sort of set up for it. And if you're using something more type based, a lot of people use Lit with TypeScript as well. So you could do checking there also.
[00:06:53]
>> Can you pass in a value up there then too or?
>> Yeah, we're getting there, we're gonna get there. Yeah, so right now, so it's an interesting thing. So when it state, it wants to be like local state, right? Like inside, this is kind of a weird thing I just sort of learned, but count wouldn't be cool if we could pass in a count.
[00:07:17]
But we don't see that, right? It's not happening, but what's weird is if I just take this out, it does work. So that's sort of the properties API's, there's local state equals true is state. And then I guess state equals false, the default would turn it into a property that you can adjust.
[00:07:43]
And this has some interesting side effects, we have not rode our buttons, but you know what? [LAUGH] One thing I kinda do is, this is my weirdest favorite part. So from the document, I can querySelector my-counter, okay? And then I can say count = 10. Weird, I can't really do that with a React component to my knowledge, [LAUGH] just like hot select it and edit.
[00:08:20]
It's internal value, that's pretty cool. It's cool to me, Dave Rupert, and just in the fact, you could change. If I had my podcast player and I just wanted to like you clicked a link, and now it shoots up into the podcast player. That could be kind of cool, I just yoink the URL, the file URL, and then put it into the component.
[00:08:42]
Kind of interesting, but let's get the local state kind of going, right? So cuz I don't know how to spell increment and decrement, we're just gonna do plus and minus. I'm smart, I swear, count++, right? Easy enough, and then our minus is going to be, minus is count--.
[00:09:07]
And then we have to go to our buttons, right? And this is a custom directive, right? Is that what they're called when it's like the thing? Yeah, okay, I get the directive and decorators mixed up. So this, but we need to use JavaScript in here. So this._plus, so we're just gonna say, when you click this @click, do this._plus, and then on this one @click, or this one's minus, sorry.
[00:09:42]
That would have missed it, that would have been a bug. And this one is this._plus, and I think this should work even with the quotes. JSX, you can get confused cuz you wouldn't put quotes there. I'm getting confused, but what's neat about this is we're able to kind of pretty quickly create a counter, allow it to be externally initialized.
[00:10:08]
So if it's your cart or something like that, it can be initialized like that from the exterior, and then we can do this plus or minus thing. But this weird state true, now, it's just a only a local state variable, it's not broadcast anywhere. So any questions, you wanna do some styles?
[00:10:36]
We can make our buttons green, cuz I feel like we've struggled with [LAUGH] buttons all day. Styles =, and then they said this works. [LAUGH] Let's try it, button ( background: green ), hopefully that does it. Hey, that did work that time, it's Christmas miracle, yes, sir
>> In the properties, the count, and then having an object and state and all that, is that specific to Lit or is that?
[00:11:11]
>> That's specific to Lit, the way it kind of works in Vanilla Realm, and this is just kind of pseudocode, static get observedAttributes. So you basically create, and I think this returns an array of count or something like that. And so basically, you're registering an attribute that you want to eventually keep track of.
[00:11:45]
And then that's an attribute changed, when that attribute changes, you get notified of the attribute changed callback. So again, sort of that issue where a props and attributes are different. It's all sort of showing up now that we're starting to author web components. And that's just sort of one maybe sticky point you need to be aware of, is just how props and attributes.
[00:12:09]
They feel like the same thing, but they're kinda different to HTML, so, yes.
>> Are there limitations on the property names, you can use whatever you want or?
>> You can use whatever you want for properties. You can use whatever you want, it may get, what if it's source [LAUGH] like an image in the actual existing property.
[00:12:33]
That might be problematic, but I could also see situations where you'd change or you'd want ARIA or things like that reflected in here, check attributes, and stuff like that. So that's a good question. I don't know how far you can break it or if it yells about something existing, I mean, we could switch this to or.
[00:13:03]
Yeah, I don't think it cares, because it's your custom element. It thinks it's a div, the browser thinks this is a div or span. It says, okay, cool, that's the div or something goes there, and then you tell it what attributes it accepts. So there may be just weird situations I'm not thinking of, but there's also in HTML, we have the data hyphen attributes, data-foo=myvalue.
[00:13:41]
This stuff all kind of is maybe as dumb as HTML seems, that's intelligently designed. Because data stuff has a hyphen, and then the elements stuff does not have a hyphen. So kind of these user authored things probably need a hyphen, but the element authored things should have a normal, unhyphenated thing.
[00:14:08]
No hard rules here, but this just interesting, so.
>> Other patterns that people generally follow?
>> No, I mean, I think it's just usually just whatever makes sense succinctly as possible, so. Cuz this is your insurance policy that no one is there. And I don't really talk about it, but there is a chance, like what if two my-counters show up on the page?
[00:14:35]
No, [LAUGH] what do we do? There's proposals and stuff like that for namespacing custom elements. So if I import this package of components, I wanted to go into this namespace bucket. I don't know the status on that, so I don't cover it, but there's kind of this idea of namespace says or sets for components.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops