In this lesson, we'll learn about how you can style react components using the style prop and className prop. We will go over how these props are differant than regular html style and class properties. Style, in JSX, takes an object, camel casing the property keys like borderRadius
instead of border-radius
.
[00:00] Let's start out by adding a div with box in it. Then we'll say style is an object with padding left at 20 pixels. This is one of the handful of differences you'll find with JSX and HTML. Rather than a string which you would use in normal HTML, we're using an object here. The property keys are camel cased rather than combop cased as you would have in CSS. The property values are strings.
[00:26] This is nice because objects are much easier to compose together than strings of CSS. We'll talk more about that in a second. Also, because the padding left value is pixels, we can change it to a number of 20 instead of a string. React will treat that as a pixel value.
[00:43] Next, we'll say classname equals box to apply the CSS we have on this page. Let's add box--small to get a small, square box. You'll notice here that we're using the classname prop. This is another one of the differences with JSX and HTML.
[00:58] In HTML, we'd use the attribute class whereas here we're using classname. If we were to extract these props into an object like this then spread them out on the div, we'd get the same result.
[01:10] Now, let's extract the classname value into a variable called classname and use object shorthand to add it to the props. Cool. It's all still working. If the classname prop were class instead, we wouldn't be able to use the shorthand here because you can't have variables called class. That's a syntax error.
[01:28] In addition, if we tried to destructure class out of the props object here, that wouldn't work either. The poor ergonomics of using a variable called class in JavaScript is one of the reasons React chose classname over class for this particular prop.
[01:42] Let's go ahead and turn this into a functioning component called box. We'll accept all the props and spread them across the div we rendered, so you can pass other props to the box component. Let's render that here with small box. Now, let's add a style prop to the box with background color light blue.
[02:01] Now, we've lost our padding on the box. This is because object spread does a shallow merge of the objects given, so the style prop given to the box component is overriding its own style prop.
[02:13] Let's destructure the props, pull out the style prop, and call the rest of the props rest. Then we'll spread the rest props onto the div. Then we'll merge the style prop with our own styles. Awesome, that works. These things are composing super well. This would be much more difficult to do if the style prop accepted a string of CSS. I'm glad that it's an object instead.
[02:36] Let's do the same for classname so we can have different sized boxes. We'll remove the box--small and instead pass that into where we're rendering the box. We'll say class name equals box--small. We're going to have the same problem we had before, so we'll need to merge these two props together ourselves.
[02:55] Let's destructure classname out and assign the classname on the div to a template literal instead. We'll say box and then interpolate the classname that we're given. Cool, that's working. There's one more consideration here. Let's remove the classname from where we're rendering the box and check out the DOM.
[03:15] You'll see that we're getting the classname of undefined. That's probably OK, but let's go ahead and clean it up. This is happening because the classname prop does not exist, so it's undefined. We'll add a default value for the classname to be an empty string.
[03:28] Now, that's gone and there's an empty space there. We could add a trim to this template literal like this to get rid of that space, but I don't really think that's necessary. All right. Awesome.
[03:39] Now, let's go ahead and render a couple other boxes, each with a different color and size. We'll do medium, we'll make that pink, and then we'll do large, and we'll make that orange. This is composing together really nicely.
[03:55] One concern I have with this is that the classname to get these different sizes has to be known by the users of the box component. It'd be much better if the users could tell the box what size it should be and then the box could apply the right classname itself. That way, all of the styling logic for the box resides in the box component.
[04:16] Instead of a classname prop, let's use a size prop where we can pass a string for the size like small. Let's destructure out the size prop and calculate classname based on that value. We'll say const size classname equals size ternary box--size or empty string. Then we'll interpolate that into our classname prop.
[04:41] Now, this box works exactly as it had before only now the relevant styling information is entirely contained in the box component. We can still pass overrides for the in-line styles and classnames. This makes it really nicely composable. Let's go ahead and do the same thing for the medium and large boxes just for good measure.
[05:00] In review, to style a React component, you can use the classname prop to assign classnames used in regular CSS styles, and you can use the style prop which accepts an object of CSS. One more important thing to note about the style prop is that the values are not vendor prefixed for you, so you'll have to do that yourself.
[05:21] There are a couple other problems within in-line styles as well. There are a couple libraries to overcome some of these problems. Popular libraries include styled components, emotion, and glamorous. I highly recommend you give these a look if you're planning on building a serious React application.