React and TypeScript, v3

Creating a Button Component Exercise

Steve Kinney
Temporal
React and TypeScript, v3

Lesson Description

The "Creating a Button Component Exercise" Lesson is part of the full, React and TypeScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Steve instructs students to transform a basic button into a fully typed, reusable design system component. He shows how to extend HTML props, add custom properties like layout, and use TypeScript for autocomplete, type safety, and implicit documentation, creating functional, self-documenting components.

Preview

Transcript from the "Creating a Button Component Exercise" Lesson

[00:00:00]
>> Steve Kinney: And let's say our design system, maybe you have a very, like a button, it would be like primary, secondary, tertiary or something like that, or danger, ghost, what have you. Here we could say something like, and layout is optional and it's like vertical or horizontal, and based on what they define that as, your component will be laid out differently, maybe you put flex column versus like a flex on it, right?

[00:00:30]
And now, counter form props is effectively everything that a form can do plus this one additional thing that matters for our design system to get everything typed the way that we want it to layout. So you can then like build on top of the HTML primitives instead of having to define every single event handler, every single ARIA tag, every single data attribute, so on and so forth, right? And later we'll talk about how to like maybe pick all but one, so on and so forth, but we haven't totally gotten there yet.

[00:01:05]
So your job is I've got a half thought out button handler that can't even take click events right now, right? And you can just take children, that's a string, and what we want to do instead is make it a spiritual successor to a button so that we can use it throughout our component as well here. So let's take five minutes to do that. We'll take five minutes to review. Everything will be great. So our assignment was to take this kind of bogus button, which we will do many things to in our time together.

[00:01:48]
This is not the last we touch this button. We take this button that right now, again, only takes a string, which is not what we want, and doesn't take any attributes to speak of whatsoever, like onClick, and rather than try to add everything I need over time, I just want it to be a button where I've got some classes that I can tweak later on. And we'll actually make variants, we'll make it a whole design system component by the end of our time together, but one thing at a time.

[00:02:21]
So to do that, obviously I could just say that this was props with children, but again, that gives me none of the attributes. So what I want to say is that this is component. I'm going to go with this one right now, and we'll say that it is a button and so now, if we kind of go, I can do like, well, we see before, I'm going to like take the props and spread them. And TypeScript, other than the fact that it would like me to call it props, and because we're spreading the children, we can do this as well.

[00:03:16]
TypeScript does not have any problem with me taking all of the props, whatever they are, and spreading them across this HTML button component, because it knows that my button component has the same signature as an HTML button component. So it's like, insofar that that's true, we can go ahead and spread all of them. So now my special button component has some fun styles, and then has everything a button can do.

[00:03:49]
So if I go back to the counter, I can then go swap it back in. So we'll go button, button, button, great. OnClick works. It knows it's an HTML button element, it knows everything about it in this case that is legit. But if we look at the actual UI, which I haven't looked at in a while, so we'll see, oh, they look like my actual buttons now, right? I get all the styles, but then I can also do like, on any given one of these buttons, I can do like literally everything that an HTML button supports as well, with again, very little code, and that's like a core piece of my design system.

[00:04:30]
It has some quirks. It has some quirks. If I were to give it a className, that would, if we look at the actual component, since it comes after className, it would blow away this className with the later one in the way the spread operator works, right? Last wins. If I move it up like this, then they can never pass in a class. Maybe that's what you want. I will show you, it's not TypeScript related or React related, but we're talking enough about design systems that I will show you at one point, how to solve for that.

[00:05:03]
But, and children is just a prop, so even when we spread it, we don't necessarily have to call it out directly. But now my design system button, other than being prettier than the built-in one, supports everything that a regular button does as well. So I think we had counter form that we need to change that button as well. Oh, we just put the input in there. Let's put our button in there. Just to show, so I can do button, right, I can do type.

[00:05:40]
You can see that works and it's submit. It has all, it feels like a regular HTML button at this point. Call that setCount. And it'll work. And so, unless I've messed something up at some point or another, and I haven't, oh, I even got increment and decrement in the right order. Look at me. So now I have a button that looks and feels, has all the types of properties of an HTML button, and it's part of my design system as well.

[00:06:03]
I've learned how to pull stuff out and like have components that are effectively inheriting stuff along the way, because like right now, even this counter props is really just a form with this layout property I don't do anything with. But what's really cool, and where I will get to with the whole like, your types are also documentation is if counter form is everything about HTML form, but also, right, the layout, that doesn't do anything, but like, I guess I could do some extra code here, but I'm not going to.

[00:06:43]
I can go in here and I can say, layout. And you can say, oh, it has a layout property, and oh, it knows the two options you can hand it are horizontal and vertical, right? So there's implicitly some like, you know, exposure of the API of this component, right? Some like inferred documentation that there's one layout property because they're typing the character L and I can see that property, and then what two options it takes for free, just based totally on my type system, right?

[00:07:23]
I'll show you one quick little extra bonus that really will go a long way as well, which is using JSDoc syntax, right? And you can use JSDoc just basically in your types and you'll get a lot of extra stuff for free as well. And so JSDoc is just technically a JavaScript comment, and you can say like a special kind of form for counter operations. And we can say layout, it should be the direction of the form, right?

[00:08:10]
And now, when I go to use my counter form component down here, if I hover over it. Don't embarrass me. We got it on that property. I'll check why it's what the issue is before, but we get to actually have, not only does it exist there, but we also can see like what the meaning of that is, right, based on the comment that I had up here as well. I think I gotta put that on the actual component because I put it on the props.

[00:08:37]
I got it, if I put it on the actual component down here. You will see, here's a way to say like, oh, layout is the direction of the form, so now the person hovering over my counter form props will say, oh, I now know what this thing does. I know that it will autocomplete vertical and horizontal. I know when I hover over it, that I will see both here and if I go down to the actual component itself, right, layout is the direction of the form, counter form.

[00:09:05]
Oh, a special kind of form for counter operations, right? You can begin to like start to document your entire like either the components you're using throughout your codebase. TypeScript is going to handle what kind of types, it'll do the autocomplete. It'll say if they made a mistake in a typo in vertical or horizontal spelled wrong or something along those lines. And then the JSDoc will step in and also give you a little bit more context.

[00:09:31]
And they support full markdown in VS Code. You can just write markdown, get bold lists, what have you. You can link to the docs for your design system if they needed to read it, so on and so forth. And by just using, again, the only real types even going on in that counter form is me extending the form properties and adding one thing to it. Not a lot of code all said and done, and like, we even get the definition of like what this little utility function is.

[00:09:58]
I get all of the autocomplete, I get all the documentation, I get all of that fun stuff. Again, super useful, you build a design system, but again, you probably have shareable reusable code in any large codebase where you're like, what is this thing? What options does it take again? How does it work? You can begin to like define all of those as well and just get all of that in context so that everyone on your team is just a little bit more productive.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now