Building a Filter Component with shadcn/ui
Learn how to compose multiple components to create a new one, such as building a filter component.
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 Sleek Next.JS Applications with shadcn/ui 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 Sleek Next.JS Applications with shadcn/ui, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:12] In this lesson, you will learn how to compose multiple components to create a new component, the Filter 1. You will add the Filter component to the events table in the new events application you have built.
[00:13 - 00:19] The filter looks like this. The Filter component is composed from multiple Shadsie and UI components.
[00:20 - 00:36] Deepop Over, which is the part being opened after the user click on the filter, debatten, the badge, the command, and the separator. The goal of building the filter is to let users filter the events table by the events location.
[00:37 - 00:45] The filter will have a button that when clicked, will display a popover with a list of locations. The user can then select the location to filter the events table.
[00:46 - 00:50] Let's start. First you need to install and import the required component.
[00:51 - 01:16] In your favorite terminal, run npshadsie and UI at latest, add badge separator and command you should already have the popover button, components but if you don't then install them as well. Now let's create a new component in components /filter.tsx and start with importing react.
[01:17 - 02:03] For the checks icon n + circle icons from lucide, import the same function and then import the badge component, debatten component. And then we want the command components which are lenty so the command empty, command group, command input, command item, command list, and command separator.
[02:04 - 02:30] And the popover content and popover trigger components. And last is the separator component.
[02:31 - 02:44] Now the second step will be to create the types. So let's export type option which is a simple type with a value and label and then the filter tropes.
[02:45 - 03:10] We need a title and options which is an array of the option type. A selected options because we can select multiple options which is an also an array of option and on change function with the value equal to an array with option that returns void.
[03:11 - 03:29] You are now ready to create a component, expert function, filter equals a component. It receives title, options, selected options and on change function from the filter tropes types.
[03:30 - 04:05] And we will return, we can immediately return a popover, a trigger, can pass the s child prop, then a button with an outline variant, size should be small medium. And the class name, we want the height to be 8, the border to be dashed.
[04:06 - 04:19] Inside the button, render a plus circle, add some margin to the right and make it size 4. Render the title and then we are going to do something spatial.
[04:20 - 04:39] Inside the button, check if the selected options length is bigger than 0. If so, we want to render the selected options to the user.
[04:40 - 05:04] If there is one item selected, we can show the label of it and if the armor we can simply show a number to not catch too much with. So we are going to render a separator with a vertical orientation and a max mx margin horizontal of 2 and height 4.
[05:05 - 05:23] Then we are going to render a badge. The badge will have a secondary variant and a class name, round the same, px1, font normal, lg, he/he, then we don't want to show it for large screens and a text white for darker mode.
[05:24 - 05:37] Close the badge. And inside of it, show the selected options length, the number of selected items.
[05:38 - 05:46] This will be shown for mobile devices. On desktop devices we want to show either the options or numbers.
[05:47 - 05:58] So let's hide it for mobile devices with the hidden class name. Add a space x1 and lg flex so on larger screens it will be displayed with a flex display.
[05:59 - 06:08] Then check the selected options length property. And if it's bigger than 2, we want to show a badge with the number of selected items.
[06:09 - 06:38] I've copied and pasted it from the top. And if it's less, we want to loop through the options array, the selected options array and render a badge that will show the selected option name.
[06:39 - 07:23] The class name would be rounded small medium, padding one, font normal, and dark text white, the same as the other badges. Inside render the option label and close the badge.
[07:24 - 07:59] Open the event stable component and import the filter component and the option tie. Then inside the event table, we need to define a state for the options, const selected locations set selected locations, call the used date root with the array of option type and set it initially to an empty array.
[08:00 - 08:28] Then let's create a new filter event variable and we're going to filter the events based on the selected locations. If the selected locations array have zero item meaning the length is falsy, we want to return true and if not, we want to filter the events based on the location.
[08:29 - 08:45] So we are looping through the selected locations array and checking if some of the locations equal to the current event location value. And instead of directly passing the event, we are going to pass the filtered events property.
[08:46 - 09:40] Now we want to add the filter components, so create a fragment here, then wrap the filter component in a div and render the filter component, pass the title location and the selected options will be the selected locations component. On change we would like to pass the locations to the set selected locations function and we also need to pass the options, the options are the locations of the events basically.
[09:41 - 10:12] We can move it to a variable here and make it a set so there will be no multiple items inside. We'll keep the list unique, so let's pass the options and close the filter component.
[10:13 - 10:28] Now rear end the app, go to the browser, refresh the page, navigate to the events page and you should see the location filter component. Now it's not ready yet, if you click on the location nothing will be open.
[10:29 - 11:00] Let's create the popover content, navigate to the filter component and under the popover trigger add the popover content. The content is actually a command list, with the options that allow searching, render the command, add the class name to the popover content with width 200 pixels, zero padding and align it to start.
[11:01 - 11:13] Under the command pass the command input with the placeholder of the title, the command input already know how to filter the items inside the command list. Let's render the command list.
[11:14 - 11:29] Add an empty state, no results found. And then we want to render a command group with the options, the selected options.
[11:30 - 11:56] If the item is selected, return the value, then check if the items include the value. Then return a command item with the key equal to the option value and an on select.
[11:57 - 12:11] Then render a command group and we will render the items inside. Loop through the options using a map function.
[12:12 - 12:20] Let's check if the item is selected so we can show it. Go over the selected options, map based on the value and return the value.
[12:21 - 12:36] It will return an array of strings, which are the values, for example, New York and LA. And then check if the option.value is included in this array.
[12:37 - 12:50] Then we want to return command item component with the key of option value. And an on select function to handle the select state.
[12:51 - 12:59] Let's call an end-elselect function with the option.value. Now let's implement the end-elselect function.
[13:00 - 13:17] Go to the component body and turn it into a function that doesn't immediately return. And create an end-elselect function.
[13:18 - 13:26] It will receive a string of the selected item value. And then we need to create a small function that will be called get updated.
[13:27 - 13:41] It will receive the previous options, the current option, basically. First the function will find the option inside the options array based on the value.
[13:42 - 13:59] We can also check based on the upper case version of the value. If there is no option and we can return the previous options.
[14:00 - 14:21] Now we can check if it's selected or not. So in the previous options we want to find inside the array the item, the same way that we did for the actual item in the options array.
[14:22 - 14:30] Now what we want to do is to create a new options array. If the option is selected that means that we want to remove it from the previous options array.
[14:31 - 14:45] So pre-av options filter, option, and keep every option value that is not equal to the selected one. Now if the option is not selected that means that we want to add it to the array.
[14:46 - 15:00] So we are going to return a new array with spreading the previous options and adding the option to the new array. Let's format it so it looks better.
[15:01 - 15:08] Great. Now we want to return it.
[15:09 - 15:31] And we want to call the on-change function with the get-updated function and the selected options, which are the previous options inside the get-updated part. Now we can go back to the command item and fix the on-select and call it once the user click it.
[15:32 - 15:44] Then we can render a div which will be the container of the actual option item in the list. We will pass a C and function because we have an easy selected state that we want to style the item based on.
[15:45 - 16:05] The items will have a small margin on the array, size 4, item center, justify center, and a border, library component. Then we want an easy selected Boolean condition.
[16:06 - 16:19] If it's true, we want to make the background primary and the text primary foreground. And if it's not selected, we want the opacity to be 50.
[16:20 - 16:29] This will be the check container, so render inside the check icon. Only if the item is selected.
[16:30 - 16:42] If it's not selected, we want to simply render nothing because the border of the div will be applied. And the check icon will receive a size 4 class.
[16:43 - 16:52] Under it, we want to render the span with the option label. That's it for the command items.
[16:53 - 16:57] Let's see it in action. Go to the My Vence page.
[16:58 - 17:09] And after you click on the filter, you can see the list of available locations. Let's filter it, for example, based on New York or Braddenton.
[17:10 - 17:15] Then we can click on one of the items. The badge will be added and the filters will be applied to the table.
[17:16 - 17:24] Only item from the New York location will be selected. We can add another filter, see the items being applied, see the badge added.
[17:25 - 17:31] And if you remember, if we'll add another item, we'll see the number of selected items. We can remove the model.
[17:32 - 17:41] One thing that we can add is the clear filters button at the bottom of the list . One can also see it on mobile.
[17:42 - 17:53] Only the number of selected locations will be displayed. So let's add a clear all button.
[17:54 - 18:15] Go to the filter component and render a conditional rendering based on the selected options length. If it's bigger than zero, we want to render a command separator, then a command group.
[18:16 - 18:34] And then a single command item that on select will call the on change with an empty array, the on change callback. We're going to center it using the justify center and text center class name.
[18:35 - 18:40] And the text will be clear filters. Let's see that in action.
[18:41 - 18:47] We can now see the clear filters item. If we click it, all the filters will be resetted.
[18:48 - 18:50] That's it. You have successfully built the filter component.