Building a search modal dialog with HeadlessUI and TailwindCSS
Show and style the search results
Search modal button02:22
Button label based on the operating system01:22
Styling the modal dialog02:29
Open the modal using a keyboard shortcut02:17
Modal dialog transitions03:30
Styling the search form03:15
Show and style the search results06:42
Navigate list items using arrow keys08:42
Show and style the search results
[00:00] Let's move on with the search functionality. Here, on the search field, we'll add an input event listener that will receive the event as a parameter and call a search function with the field value. To get the field value we can do
[00:20] Now let's go to our setup and define the search function, but before we do that, let's define our results reactive object to store the search results; this will be an array. Let's add the search function, we'll receive term as a parameter, and then make an axios get request to the endpoint that will return the results. In my case, I have this dummy endpoint at
tallpad.test/search. To send the term as a query parameter we can pass a second object that will have params, and then an object with the term key containing our search term. Let's console.log the results, and since we're using await, we'll have to turn this function into an async one, and then make sure we import axios. Then let's expose the results, and the search function, go in the browser open the modal, open the dev tools, type something in, and here's our request. We're passing term as a query parameter, and if we look at the logs, we see the results being logged in.
[01:22] Back to our search function, we can use the structuring to get the data, and then
results.value = data;. One thing I want to do is make sure we debounce this function so it's not being called with every keystroke. We'll do debounce, paste in the function, and let's say 250 milliseconds. Let's import the debounce function from lowdash, go in the browser, refresh, open the vue dev tools, open the modal, and type in laragel. The results are empty but if we refresh, here they are.
[02:01] Moving on, let's add a list and loop through the results to display them. We'll go here, under the form and do ul, and we'll only show this if we have results. So
v-if="results.length > 0", then we'll do
v-for="(item, index) in results", we'll set the key to index, and then we'll have an image where the source will be
item.featured_image, the alt will be
item.title, and then we'll have a container with one div for the title, and another one for the item category. Save, and the results appear but the form is a bit broken. The search icon and escape button are centered to the modal instead of just the form input. That's because these two are absolute elements and the form is missing the relative class. Let's add it, and the issue is gone.
[03:03] Another problem has to do with the images not being displayed. So let's scroll down to them and here's the problem; it should be featured image. Save, and here they are. Let's continue styling the results. For the li we'll do
flex item-center px-4 and
py-2.5 for padding. The image will have
rounded-full object-cover. We'll also add a white border using
border-white border-2 and to prevent the image from shrinking, we'll add
shrink-0 and let's also add the
bg-gray-200 to show like a placeholder while the image is being loaded.
[03:51] For the title and category container we'll just add a bit of left margin, then for the title we'll have
font-semibold text-gray-600, and for the category we'll have
text xs text-gray-600 and
mt-1 for margin; and here they are.
[04:13] It would be nice to have like a border separating the items, so let's go to our list element and add
divide-y divide-gray-100. Now the list looks somewhat nice, but if I try and scroll it, it doesn't work. To make the list scrollable we need to do two things: the first is wrap it into a parent container that has an
overflow-auto class, and the second is to make that container take the remaining space of the modal. To do that we can go to our modal container and turn it into a vertical flex using
flex flex-col, save, and here it is, we can now scroll the list.
[04:55] Another thing that's missing is the anchor tag. We want the whole list item to be clickable. To do that we can go to our li element and add an anchor tag, fill in the href attribute, and then inside it we'll add a span
absolute inset-0 and make the li relative. Now if I go into browser, we see that the whole list item is clickable.
[05:30] One last thing I want to do is to add a message for when there are no results to be displayed. I'll go here under the list and say
<p v-if="results.length === 0">No results...</p>, and let's style it a bit. We'll do
pt-20 text-lg text-center text-gray-400. Let's test it out, and here it is.
[06:08] Finally, let's make sure that when we open the modal the results are already there. So we'll go to our setup and let's say on
onMounted(() => search()). Let's make sure we move these two after the results and search function, save, refresh, and here it is.