This video is available to students only

Build a Custom Design System With React Styled Components

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Previous LessonBuild a Custom React Button Component With forwardRef APINext LessonValidate React Props With PropTypes and TypeScript

Lesson Transcript

  • [00:00 - 00:13] Now that we have a flexible API to control our button component, let's add the relevant styling from our demo application. We will be using style components as our CSS and JS solution and including custom props for controlling each style.

  • [00:14 - 00:21] Using the demo application, we can identify four unique style combinations. These styles can be represented by a few different props.

  • [00:22 - 00:35] So if we look at variants, we can see a potential variant prop that has three values, secondary, primary, and danger. We can see a size prop with values small, medium, and large.

  • [00:36 - 00:41] There is a disabled state that affects all sizes and variants. So this would just be a Boolean.

  • [00:42 - 00:55] And there would also be a full width variant, which can be used in tandem with all of these. So that would be an isful with prop that is a Boolean as well.

  • [00:56 - 01:08] So with these values, we're able to create a custom prop interface for a button component that reflects the styling. One thing to take note of is the disabled prop is already included by our component props without ref.

  • [01:09 - 01:16] So we don't need it explicitly to find it, but it will be available later on. So let's start with creating that custom interface.

  • [01:17 - 01:30] So we're going to be exporting this interface as well, since we're going to be using it with our styled component style. So we have this new button props interface, and we want to include all of the existing component props for a button.

  • [01:31 - 01:44] So we're going to extend that interface and use button refs, button props in its place. And then here we can add in our three different props.

  • [01:45 - 02:12] So we would have variant, which is going to be an optional enum with secondary, primary, and danger as values, size, which is another optional enum for small, medium or large. And then is full width, which is going to be an optional Boolean.

  • [02:13 - 02:20] And then disabled, we don't need include because that's already provided by component props without ref. So here we can call those out, so we're not applying them to button.

  • [02:21 - 02:36] So variant, size, and is full width. And then one other thing we can do is provide some default values using the default props.

  • [02:37 - 02:42] So we can provide a default prop for variant. We would want this to be secondary by default.

  • [02:43 - 02:48] Because let's use medium as a standard. And then we do not want it to be full width by default.

  • [02:49 - 02:55] So let's make is full width too false. And then we'll be using these values once we define them in our style component .

  • [02:56 - 03:08] So now that we have our style interface determined, we can add in style component store code base. So similar to react and react DOM, style components requires us to market as a peer dependency.

  • [03:09 - 03:21] So we can include that with MPM install, save peer style components. And then we also need include the type definitions for style components.

  • [03:22 - 03:33] And this will just be a dev dependency. And then along with style components, we're going to be installing a library called polished.

  • [03:34 - 03:58] So polished allows us to perform style calculations at runtime, where if you've used something like SAS or less before, they had built-in functions that allow us to do this at build-time. But we need to do the same logic just in the runtime environment so we can MPM install polished as a standard dependency, since that will be something that we use at runtime.

  • [03:59 - 04:04] There we go. One of the other things that we need to do is create some shared style utilities.

  • [04:05 - 04:22] So even though we're not writing our styles in traditional CSS, a lot of the same best practices from CSS and pre-processors still apply in CSS and JS. So our demo application provides several colored constants in a variables.sas file for use across all of its components.

  • [04:23 - 04:33] And we're going to migrate these SaaS variables to TypeScript for use within style components. So under source, let's create a new folder called utils.

  • [04:34 - 04:48] And then here, let's create a new styles.ts file. And we can create some constants that are the equivalent of SaaS variables or less variables, if that's what you've used before.

  • [04:49 - 05:00] Now that we have our shared variables, let's actually create our styling for the button component. So within the source button's directory, let's create a new styles.ts file.

  • [05:01 - 05:08] And this can be TS since we're not going to have any JSX in it. And this is where we're going to put all the style logic for the button component.

  • [05:09 - 05:18] If we look at the existing styles in the demo application, we can identify some initial styles that are provided regardless of the different style variants. So let's create that by default.

  • [05:19 - 05:31] So first of all, let's import style from style components. Let's import the props from our button component.

  • [05:32 - 05:47] And let's import one of the style constants from utils styles. And we're going to be using the disabled opacity constant first.

  • [05:48 - 06:01] So what we're going to be doing is creating an export, which is a style button component. And this is going to be a native button that includes styling provided by style components.

  • [06:02 - 06:13] And for the props available on this, let's use our button props from the button component as the default interface for that. And then let's include some default styling from the course.

  • [06:14 - 06:21] And this will align with what exists in the button.sas file. So we have some default styling that's applied all the time.

  • [06:22 - 06:34] And then the style components, we can reference the ampersand to target the existing element that we're styling off of. So whenever the style button is focused, we don't want to include an outline by default.

  • [06:35 - 06:54] And if the style button is disabled, we want to apply an opacity of disabled opacity. So next, let's go back to our, let's save and go to our button.tsx and import that new style button component from the styles file.

  • [06:55 - 07:03] And what we can do is just replace the button, the native button with our style button. Ref should be the same since this knows that it's returning a native button.

  • [07:04 - 07:16] And we can do variant. variant size of size and is full width of this full width.

  • [07:17 - 07:21] So we aren't applying any styles based off these props yet. We're going to be doing that later.

  • [07:22 - 07:34] But this hooks everything up to where we don't have to worry about it later on. So one other thing that could be useful is going to the button story that we have.

  • [07:35 - 07:43] And then what we can do is apply a default prop or an argument for this story. So for the default story, let's go and modify one of the arts.

  • [07:44 - 08:03] And just to make sure that disabled is visible, since it doesn't show default react prop types by default, let's go and say disabled is false and this will make it show up in our UI. So to get that started, let's run npm run storybook and wait for that build to finish.

  • [08:04 - 08:14] And we should see once this has done a new prop sheet allowing us to toggle some of these different values. So if we go to docs, we can see some of these style variants applied to it.

  • [08:15 - 08:21] So right now variant isn't doing anything. Size isn't doing anything is full width doesn't do anything.

  • [08:22 - 08:34] But disabled does have some styling applied to it from our styles.tsf file. So if we toggle this, we can see some styles being applied and the native attribute being applied to the element which actually disables it.

  • [08:35 - 08:43] So that means our style components are hooked up correctly. So next up, let's add in some is full width support.

  • [08:44 - 09:02] So if we look at the is block class and our fun.sass file, and this is available within the demo style guide, we can see some of the disabled properties are set. That is full width as well.

  • [09:03 - 09:05] Let's take a look at that. So is block effects display and width.

  • [09:06 - 09:16] So what we can do is modify our display and width attributes that are provided with install buttons. So for display, we can add this in.

  • [09:17 - 09:29] So actually notes up here. So in line block, so we can since we're in a JSX template here or a template literal, what we can do is just define a method directly.

  • [09:30 - 09:50] And so using the props that we get, P, we can say, if P dot is full width, if the is full width prop is defined, we want to render block as the display, otherwise display. And line block.

  • [09:51 - 10:19] And then for width, we only want to provide a specific width, which would be 100% if is full width is provided. So now if we do the is full width, we now get a full width button.

  • [10:20 - 10:27] Next, let's add in the size prop. And we're going to implement the similarly to full width.

  • [10:28 - 10:39] So this will mostly affect the padding in the font size attributes. So rather than doing a ternary, we can actually do a more traditional conditional inside this element.

  • [10:40 - 10:55] So padding, if P dot size is large, we provide both X and Y padding, if it's small and if it's medium, you do the same thing. And then this also needs to affect the font size, which rather than being one, we can change that based off the size as well.

  • [10:56 - 11:08] So if we save that, we can see small, medium and large being available as well. And then next would be the style variant.

  • [11:09 - 11:19] And this is going to be a little bit more complex since it changes many different CSS values. It also affects the focus visible data selector.

  • [11:20 - 11:26] So what we need to do is actually run some color competition at runtime. And we can use that with the Polish library.

  • [11:27 - 11:41] So starting out, let's import from polished the transparentize method. And this is going to let us apply some alpha to colors.

  • [11:42 - 11:51] And then we're going to create a style utility function called color styles. I'm going to bring this in from our docs.

  • [11:52 - 12:06] And then we're also going to need some existing style constants as well. So we can include those in from utils style.

  • [12:07 - 12:25] And then we also need to include a CSS import from style components. So what this does is it would take in the current props and then it's going to compute based off of those props, which values we should be providing, and then include a CSS block of those same values.

  • [12:26 - 12:41] So since we're creating this in a function separate from our style element, we need to use this CSS import. And so then this is going to include based off of what color variant we have, the default color, background color, and border color.

  • [12:42 - 12:59] And then when focused, it's also going to override the border color and apply a box shadow that has some alpha applied to it from the preconfigured background color. And we can include this in our element by at the bottom of everything here, just applying it directly.

  • [13:00 - 13:05] And we should see those new style variants applied. So secondary is the default.

  • [13:06 - 13:10] We include primary. We can see the different color applied and danger.

  • [13:11 - 13:19] And we can use these with other props as well combined. So let's say we wanted a large danger button that was full with.

  • [13:20 - 13:30] That's a possible combination that we can use. So now that we've included the style variants for a basic button component, let 's go ahead and commit our changes and save our progress.

  • [13:31 - 13:37] And then in the next lesson, we're going to learn how to ensure that our prop types are enforced for both TypeScript and JavaScript consumers.

This lesson preview is part of the The newline Guide to Building a Company Component Library course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

Unlock This Course

Get unlimited access to The newline Guide to Building a Company Component Library, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to Building a Company Component Library