How To Add An Ant Design System Form To A React App
While these components require a little more effort to get working, the improvements they provide are worth the time.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo 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.
This lesson preview is part of the The newline Guide to Modernizing an Enterprise React App 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.
Get unlimited access to The newline Guide to Modernizing an Enterprise React App, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:12] We've got some practice bringing in basic components from the Ant Design System to replace our own custom-styled components. Now it's time to take it up a notch, because Ant doesn't just do simple components.
[00:13 - 00:30] It also boasts robust, complicated ones too, that drastically reduce the amount of code devs have to write themselves. We'll take some of the more complex components in our app and replace them with Ants versions, and you'll be amazed how much less you'll need to make them work and look good.
[00:31 - 00:41] Forms are always needlessly complex. When I think about hardware handlers' more complicated components, the first one that springs to mind is the product form component.
[00:42 - 01:00] Forms are always complicated, whether they're written with React, View, or plain JavaScript, because there are so many requirements between input types, validations on the client and server side, and more. But AntD can really help simplify this situation, so let's get going.
[01:01 - 01:14] Before we start replacing the form inside of our product form.js, let's take a good look at the AntD form documentation. There's a lot here to take in, but they've got examples of all the pieces we'll need inside a form.
[01:15 - 01:26] The form itself, the inputs, the selection drop down, all of it. So the first thing that we'll want to do with our product form is import all of the AntD pieces that we'll need.
[01:27 - 01:47] So if we switch back over into RBS code, we're going to import the following AntD components to our own product form.js. So go ahead and open the form up if you haven't already, and right after the button and notification imports, let's add a few more for form, input, and select.
[01:48 - 02:14] Okay, so this next section is going to be a bit of a doozy, but we'll try to do it in an organized fashion. Inside of RJSX, right down here on line 71, we'll want to begin replacing our components with Ant components, and we're going to start with our form element. So on line 80, right here, this form is going to become a capital form.
[02:15 - 02:35] And then underneath that, we can replace the unordered list, the list item, and the label with one Ant option, which is going to be form.item. Form.item takes in a label to show in the browser and a name that is like our previous label elements, HTML4 property.
[02:36 - 03:01] So here's what it will end up looking like. We will have form.item, and it will have a name, which we will set equal to department, and also a label, which we will also set equal to department. We will take this form closing tag and move it down to underneath this select where this orphaned line item ending is.
[03:02 - 03:22] Replace that, and then at the very bottom, we will remove this unordered list because we deleted that as well, and go ahead and give that a save, and prettier, we'll reformat it. Now we come to our first form element to replace the department select. Lucky for us, the Ant D select is quite similar to our current one.
[03:23 - 03:35] It accepts a placeholder text, a value, and an onChange function, just like our original element. So if we look over here in the browser, here are some examples of different selects.
[03:36 - 03:56] If we look over here in the browser, we will see the placeholder text, the value, the onChange function, just like our original element, and the options that are inside of our select become select.option elements. So if we head back over into VS code, here is what the rest of the form element will look like.
[03:57 - 04:19] And don't forget the closing tag. So this select is going to become a capital select from Ant, so we're going to be able to remove this class name as well as this ID. We will keep the value, and we will also give it a new placeholder text, which will take the place of our HTML placeholder.
[04:20 - 04:36] So we will just grab that, please select a department, and we will paste it up here inside quotes, and we will leave our onChange unchanged. Once we have done that, we will remove this option completely. We no longer need it.
[04:37 - 04:53] We will still do the same departments.length is greater than zero check, and this option will now become select.option. The key stays, the value stays, the department name stays, everything else stays.
[04:54 - 05:11] So now we'll do the same replacement for the rest of our form inputs. Our next form input for the product name should look like this when we're through. We will take this line item of class name and this label, and remove both of those, and replace them with form.item once more.
[05:12 - 05:48] The name will be equal to product name, and the label will also be equal to product name, but with the proper capitalization closing tag, and then take this form item closing tag, copy it, and replace this closing line item. And then this input inside of it will become a capital I input. We will get rid of the class name and the ID and the type, and be left with the placeholder, the value, and the onChange function.
[05:49 - 06:02] So this form item should look similar to our first one, and the ante input also accepts placeholder text, a value, and an onChange function. Our brand description and retail price inputs should look very much the same.
[06:03 - 06:24] If you'd like to, I'd encourage you to take a shot at replacing them yourself, and then check my code below if you get stuck. Here is how I'd replace the next three inputs. We would remove this one for and create a form.item with a name of brand and a label also of brand.
[06:25 - 06:44] Take this form.item, copy it, and paste it into our line item right there, and then this input becomes a capital. We remove the class name, the ID, and the type, and you are left with the placeholder, the value, and the onChange.
[06:45 - 07:00] The same thing is going to happen for description.form.item.name=description. Label=description.
[07:01 - 07:10] The form item replaces the line item, and text area is going to become input. text area.
[07:11 - 07:39] It has one just for text areas. Once again, class name, ID, and type can disappear. We'll let VS code reformat that for us with prettier, and our final form.item will have a name of retail price and a label of retail price.
[07:40 - 08:01] We will remove the closing line item tag, and this input will become capital, and we will also remove all of these unnecessary values. Notice that there is a special input.text area component to replace traditional text area elements, but the rest should feel relatively familiar.
[08:02 - 08:15] Finally, wrap our "ant submit" button in a form.item tag as well. There is no point leaving it as the only line item inside of our form. So this line item will become form.item. We don't need to give this one a name.
[08:16 - 08:33] We just need to wrap it in a form.item tag, and finish off that one line item. Okay, everything about this form has become an "ant" component. We are off to a really good start. Let's add some small details to make sure that this form continues to work the same way.
[08:34 - 08:58] One thing that we can do with "ant" forms is indicate to users which elements are required. By adding a certain line of rules required true to a form item element, a little red asterisk will appear next to a field to indicate that it must be filled out. So we need to add this line to our product name, our brand, and our retail price form elements. So let's go ahead and do so.
[08:59 - 09:28] So if we're going to start with our department, we will inside of our form item add a "rules = curly brace, bracket, curly brace, required true. And then go ahead and copy this, and we are going to add it to everything else that needs it. So product name, it's required. Brand is required.
[09:29 - 09:49] Description is not required, but retail price is required. Go ahead and save that and let it reformat. And now let's test our form and see if it still works . We'll take care of the styling after the functionality is confirmed. So if we head over to our React app, I've already started it up, but if you haven't, go ahead and do "yarn start".
[09:50 - 10:18] Head over to the browser and go to the "add new products" page. And this is okay, but if I try to select something, we're having an issue. There's an error in the browser. The error is happening because the "ant" select just accepts a value and not an "e.target.value" when you look closely at the actual functionality in the "ant" documentation.
[10:19 - 10:48] So this is easy enough to fix in our code. Head back over into VS code. We will change this on change to "save value" instead of "e". And then we will just have "value" instead of "e.target.value". Okay, now let's test our product form again, back over in the browser. And this time, you should notice after we have selected our tools that our retail price accepts a lot more than just numbers.
[10:49 - 11:07] See what I mean? It turns out that "ant" has a special input just for numbers that I was originally unaware of, and it's called the "input number" component, aptly named. So switch back over to VS code and import input number at the top of your file.
[11:08 - 11:40] And once we've got that, we will add this down for our retail price. So instead of input, it will become input number. And input number also will accept a minimum, so we will set the minimum to be zero. The retail price will stay the same for the placeholder. Value will stay the same. However, our "on change" also changes from an "e.target.value" to just straight up value.
[11:41 - 12:07] Okay, so far, so good. So let's do one more test of our application with our new options. And if we come back over, we will select... So at this point, the product should be successfully added, but the form is not very good looking. If we submit that, our new product gets added.
[12:08 - 12:22] So, not to worry, "ant" has some very handy form styling that even its most basic forms can implement. By default, "ant" forms have a horizontal layout, but if you need vertical or inline styling, that's available too.
[12:23 - 12:45] So what we need to use is the label call and wrapper call properties. Let's take a look at these. So if we open up our code right here, we will see that we have form layout, use state of horizontal, and the label call with the span of four and the wrapper call with the span of 14.
[12:46 - 13:04] These properties follow the 24 column layout system that "ant" makes use of, similar to Bootstrap's grid, if you've ever used that before. To make these new "ant" form elements look like our previous ones, nicely aligned in the center of the page, we'll apply the following styles to our outer form element.
[13:05 - 13:37] Go ahead and head back to your VS code instance. And at the top of our JSX, where we declare our form, we are going to give it the following properties. We are going to remove this class name of product form, it's no longer needed, and we're going to give it a label call equal to double curly braces, span of 10, and a wrapper call of double curly braces, and then span of four.
[13:38 - 13:52] So this will filter down and style all of our form items except for the button. I'm not entirely sure why the button doesn't get the same style applied, but we can fix that with an extra line of code on its own form.item as well.
[13:53 - 14:17] So let's scroll down to where our button is, and right here, for this form.item , we're going to add a wrapper call equal to double curly braces offset of 10. So this offset will line up our button nicely with the rest of the form, and we can delete a whole bunch of what used to be needed CSS in the product.css file.
[14:18 - 14:33] These classes no longer exist. Let's take a quick look over at our product file now and tell me that that doesn't look better. That's beautiful, right? And it was really simple to do with ant. So let's get back and rip that CSS out. There's nothing that makes me happier.
[14:34 - 16:27] here. Okay, so pop open your productform.css and let's get to work. Here's what we can now delete from the product form. Starting with line 13, we can delete the product form list, the product form list item, the product form list item label, the product form input and the product form drop down. Fantastic. In the end, our newly refactored form looks so much better even with all of our deleted CSS. That's pretty nice, right? Look how much less code we can get away with courtesy of Ant. Okay, so let's see what we can do with our product filters because another more complex piece of our app is that product filtering system in the product list component. It is a perfect candidate for a few Ant checkboxes. If we look at the Ant checkbox design, they 're pretty basic. We have a checkbox that we import from Ant-D. It takes in an on change and that 's about all there is to it. Even the checkbox array isn't too bad. It still takes in an on change function. It has an array of options and then it has labels and values. That's about all there is to it. So let's go back over to VS code and we'll begin to swap out our checkboxes with smaller sets of the two sets of checkboxes, the department filtering ones. If you review the Ant documentation, you'll see that the checkbox.group element takes in an array of options to render, which is not too different from what we're currently doing with our home spun set of filters. So we will pop open product list .js and at the top of our file, we will import checkbox into our list of Ant-D components and then we will find the department filter in our JSX, which is right around line 116 or so.
[16:28 - 19:00] Here we go. Here are our filters by department. So the Ant checkbox is going to dramatically simplify what we have to do to make these filters render. There is no mapping over elements required. No separate labels or inputs even. All Ant checkbox.group needs is our array of options and our on change function. So our code is going to become not error and filters by department .length. The bat will stay the same, but instead of all of this, so this whole thing will become checkbox.group and the options will be filters by department. Our on change will stay on filter change and our class name will remain as filter-item and then we will close that up and that's it. So now if let's check the browser and see what happens. We head over to our react and we go to our browser window, my products fails to load. I encountered this same error and it took me a little bit of debugging to figure out what went wrong. The issue turns out to be the fact that Ant components expect an array with the properties of label and value. Our current department's array that we're passing in has the properties of ID and name. And because this same array is used in other places in the app, I don't feel comfortable changing it at the base level . We'll change it before we set it into our local component state instead. So head back over to VS code and inside of the use effect on line 40 where we check if our use department's hook has returned, we're going to set our local filters by department state. If it has, we'll add a small function that will map over our department data and rename it into the object that the Ant checkbox element is expecting. So our use effect right here is going to go from setting departments right after department length is false. We're going to create a new function that is called const depth filters. And this will take departments and map over them. And so each individual department will be inserted into this new object that we're creating, which is just an empty object.
[19:01 - 19:19] And we will say new object equals a label with a depth.name and a value of depth.id. And then right after we have created that, we are going to return new object from this function.
[19:20 - 20:07] Set loading will continue to be set to false and instead of set filters by department being set to departments, we will change that to depth filters. So go ahead and save that. And let's check the page again. Our department checkboxes are loaded. At this point, let's hold off on checking if the filtering works. Let's get the rest of our checkboxes based on brand name replaced first. So head back into your VS code. And after replacing the department checkboxes, replacing the brand name checkboxes should be similar. So our brand name checkboxes inside of our JSX will end up looking something like this. We will take all of this and instead it will become check box.group.
[20:08 - 20:27] Our options will be filters by brand. Our on change will be equal to on filter change. And our class name will also be equal to filter dash item and then close that element up.
[20:28 - 20:54] So the filters by brand array that we pass in has the same issue as our first list of options. However, this object is only being used in this particular component. So I feel more confident changing it at its source to have the required object properties. So follow the filters by brand object back through the use products hook to our format filters function, which is right here.
[20:55 - 23:27] And this is what actually creates our object. So we only need to do a one line change here and in the use products file and will be good to go. So in format filters, make the following adjustment to the item to filter by variable. It is going to go from name to label and it will stay product peram and value will actually stay completely the same. So then in our use product hook swap out the property that the filters are being sorted by, we will go from name to label in both instances and go ahead and save that. And with that small adjustment, our brand filters should correctly be rendering. Fantastic. So now we're on to testing our filtering. The filtering doesn't work worth the darn currently and it took me quite a bit of time to figure out what exactly was going wrong with it and how to resolve it. Here's what I eventually learned was going on. When a user checks one of the checkboxes in a checkbox.group element, an array is populated with that value. So checking the checkbox next to the hand tools department would give you an array of the number one. When the next checkbox in that group is selected, the array is replaced with a new array of one comma two. If the same checkbox is unchecked, a third new array is created with just the value of two. Whatever is added or removed, ant takes care of under the hood for us. Same for the checkboxes grouped by brand name. However, there is no way to combine these two arrays to use the same on filter change function because we don't know what value was removed from the array of values to filter by, which was how we kept track before. So here's the solution that I came up with. Split the on filter change function into two with two sets of filters that we combined together to do our actual product filtering in the end. A little confused, it'll make more sense when you see the code. To start, let's create two arrays to hold our selected filter values. So on line 23 of our file for product list, all the way back up at the top, we are going to replace the active filter variable with two new variables. We're going to have active brand filter and set active brand filter.
[23:29 - 24:19] And we are going to also have active depth filter and set active depth filter, both of which will begin their lives as empty arrays. Next, we'll replace our on filter change function with two smaller functions. If we scroll down to where we've got our on change going, right here on line 93 on filter change, we are going to make two new functions. We are going to have on department filter change, which will be a function that will take in a filter argument. And it will set the active department filter to whatever that filter array is going to be, which will provide to us.
[24:20 - 25:08] Same for the on brand filter change function. It will take in the argument of filter or filters and set our active brand filters to whatever that array might be. Now we can go ahead and delete this on filter change and all of its complex functionality that it was handling for us. So one more thing is don't forget to replace these new on department filter change and on brand filter change inside of your actual JSX. So our first one will become on depth filter change on line 125. And then on line 136, that will become on brand filter change.
[25:09 - 26:40] Finally, the filtering that we do right before we render our component will get a little more complex because we will have to combine the results of our two filters and compare them to all of our results. So if we look at this big old if block here on line 103, these active filters are going to become active brand filter and active department filter. We'll do active brand filter dot length plus active depth filter dot length is equal to zero. And then I will just copy that and we will replace it down here. And then the same for in here, we will say if active brand filter includes item brand or active depth filter includes item dot department ID, then change the filtered list to reflect that. And if we look over in the browser and test our filtering looks like it's working. Fantastic. Okay, so the current styling of our filter leaves a little to be desired. It's not the greatest looking thing. We can definitely do better. So let's get them back in a vertical column and give them some padding. They're looking a little squished together right now. Our filter checkbox class got completely removed. So we can delete that code out of product list dot css.
[26:41 - 28:29] Open up your product list dot css file and go ahead and remove the filter check box right here on line 25. We'll remove our flex properties from the filter data class. So no display of flex, no flex direction and no flex wrap. Take all those copy them and put them into the filter item class instead. Just pop them down there and we can get rid of the grid and the margin properties in the filter wrapper class as well. So we no longer need grid area or margin of auto. Delete those. And last but not least, we're going to add two ant specific classes to add some padding and let these checkboxes breathe a bit. So for filter wrapper, we're done with that filter title will stay the same. Filter data will get in addition to its border top a padding of 0.5 rims 0 1 rem and 0 to give it a little bit of extra room and filter item. We will be able to remove this margin and this flex wrap and we will instead add an ant checkbox wrapper which we will give a padding of 8 pixels and 0 and we will give an ant checkbox class a padding of 0 and 8 pixels and then the rest of it should be able to remain the same.
[28:30 - 28:43] So if we check back over in our browser now, doesn't that look a thousand times better? It sure does to me. Excellent. We are done with this lesson and with this module. Well done.
[28:44 - 29:06] Well done. I hope that after these last couple of lessons, you feel better about navigating a design system and using the documentation to leverage the components that it provides. It takes a little getting used to but once you see how component libraries can simplify your own code, you can see how worth it they can be. We'll wrap up this module and then the whole course.
[29:07 - 29:08] You are home free now.