Lesson Description
The "Button Props" 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 introduces the concept of mirroring HTML props to simplify the process of building components that wrap HTML elements. He explains how to extend component props without ref to include all attributes of a form, demonstrating how to avoid implementing each one individually. Steve then instructs the students to apply the same technique to the button element, emphasizing the efficiency gained by creating components as a superset of HTML attributes.
Transcript from the "Button Props" Lesson
[00:00:00]
>> Steve Kinney: So like, again, where trying to use something like TypeScript or whatever might start to feel cumbersome, I would then challenge you to be like, okay, is there a simpler way to do that? And that's why we're in this course together, is to figure out the simpler ways to do it. What if instead of for this button that I'm not really using just yet, or for the form, what if instead of trying to, let's say that it is like if you're building a design system, you might have a button.
[00:00:30]
Like arguably that is the canonical component in a design system. It's probably the first one you make is button, but you might also have a form. So if we look at button, we go to HTML button attributes. You can see that it's got all the attributes of an HTML element, all the ARIA tags, all the tab index, so on and so forth. And it also has all of these button-like things. That's that one that we were joking about earlier, Scott, the do not use or you will be fired experimental form actions.
[00:01:07]
We don't want to, like, we don't have to re-implement all these things ourselves. So if one was building a design system with React and TypeScript, the like, you know, that meme where it's like, the brain gets bigger and it's galaxy brain, like the first panel on that is, I'm going to put an onClick on my button handler, and then I'm going to put an ARIA role on there. I'm going to put every prop one by one on a component.
[00:01:33]
And that's where you're like, I hate TypeScript, I'm not doing this anymore. And either you have an incomplete button element or you give up, or whatever. And I want to show you that actually, in the same way we saw before that you can have like all of these types are just types that we can use, we can actually say that this button element that we're going to work on in a second is not only our special props from our design system, but also, it should also take all the props that a button takes.
[00:02:05]
That way you're not implementing them one by one and hoping that you have it exactly right, so on and so forth. We can say that our counter form props is actually going to take just like, sure, maybe it takes like one or two extra things like what variant or what size or what layout you want for that are unique to your design system or your components, because again, maybe you're not working on a design system, but you probably have some components in your codebase.
[00:02:30]
And probably some of them just wrap various HTML elements, and you want them to be able to also, because this is like counter form wraps a form, right? And we had on submit, but forms can do a lot of things. If I wanted to have all of the attributes of a form, plus anything else special that we care about, I need a way to do that. And luckily, there is a very easy way to do that. So let's do it. And this is, we're going to kind of call this, it's tricky what the actual name is.
[00:03:04]
We're going to call it mirroring HTML props, right, or HTML attributes, right, so that we can have our components that become like a superset of all the things in a given HTML element. So we can do that. I'm going to do it to the form and then I'll have you do it to the button. If we remember all the way back in our brain cells earlier, we had that props with children. Do you remember that one? That was to say like, hey, this takes some props and also we'll correctly type children to be optionally React at ReactNode.
[00:03:48]
Turns out React has a bunch of other utility types that make stuff easy for us and we'll also learn later how to make our own when React doesn't, but let's start with one that is incredibly useful if you, again, are building components that should wrap HTML elements and you don't want to necessarily like have to add support for every single data attribute you might want. You want to be like an HTML button with a few extra things that I care about.
[00:04:16]
It's a very, very, very common pattern and where I see both previous younger versions of myself, my teammates and stuff along those lines, make some interesting choices. So I will do it to this form and you will do it to the button, which is, again, we just basically try to re-implement one tiny little slice of an HTML form component. What we can do is you've got ComponentProps, and you've got ComponentProps with and without ref.
[00:04:46]
I usually tend to prefer without the ref because you can use like a forward ref, higher order component and use imperative handler and a bunch of other stuff that is nice for design systems if you're using a ref, and if you're not using a ref, then there's another compelling case in why ComponentPropsWithoutRef is in there. But like, use that one or I don't know, use the other one if you really care.
[00:05:10]
I like this one. So ComponentPropsWithoutRef and we can see that it's angry at me because it does take some type of generic, which is an argument for a type, and that should extend React element type. You're like, what is that? I don't know, right? And so we do the braces, if we start with a string, we can basically say ComponentPropsWithoutRef will basically say take all of the attributes from a form, get me all of them as props.
[00:05:45]
And so now if you look, onSubmit is not a red squiggly line of sadness, right? OnSubmit is exactly what we typed it earlier, right? In fact, anything that a form can do, right, and again you can kind of hit a button and get IntelliSense to tell you, it now has all of the events and all of the properties of a, you know, a className, children, so on and so forth. All the ARIA tags from a form, and you didn't have to implement them all one by one.
[00:06:23]
You're saying like, hey, this takes everything that a form does. And if you wanted to extend it, you can either use that intersection that we saw before with the ampersand sign, or again, if you like interfaces, this is arguably a really good place for an interface. We could say that counter form props that we had earlier, let's make that an interface just for fun, extends ComponentPropsWithoutRef form.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops