Nuxt 3 Fundamentals

Using Slots

Ben Hong

Ben Hong

Nuxt 3 Fundamentals

Check out a free preview of the full Nuxt 3 Fundamentals course

The "Using Slots" Lesson is part of the full, Nuxt 3 Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Ben introduces slots and demonstrates how they allow parent components to pass content into a child component. When multiple slots are defined within a component, they can be given names and explicitly targeted using a template tag. Slot-specific props are also discussed in this lesson.


Transcript from the "Using Slots" Lesson

>> So app.vue right here, we can see that we have just the generic components here side by side. And so for the todo viewer, I wanna start giving you at least a little bit of insight on how you might abstract some of that functionality. So for example, for todo viewer, we have here that we have this title right here, hello friend and masters, but maybe something we want to be able to customize.

So we need to define props. So all we need to do to do that using the composition API is a helper function called define props as you would kind of expect. So to find props is basically a function that takes an object. And this is how you normally define props in view, basically on a standard, so basically call it a title.

And what kind of title will it be? It'll be a type string and I'm just gonna make it a you know, I'll do I'll make it a default of hello front and masters. So in other words, if the person forgets to pass one in, it's fine, the title will get rendered, otherwise you don't need to do that.

And so for those who haven't used view a lot, another attribute that's possible is something called required true. But typically my recommendation is, if you have a default the required true is kind of redundant because it basically means you're guaranteed to have it. On the other hand if you have no default and it is required, then basically you'll need to throw the required on.

So, basically you should never see these two really side by side it should really be one or the other. And so, in this case, we have a default so we're good. So, to show it to actually render that thing, we can go ahead and just replace hello friend and masters with the title attribute.

And to prove that this works, we're gonna come in here inside of our todo viewer. Okay, and we're gonna do the title and this time we'll say, this is fun, save. Now, when we come over here and refresh, something's broken. Undefined text color variable. That's a separate thing that broke and that has been broken into the viewer.

Okay, that's totally fine. And that actually does make sense because he left a bunch of styles here. That we were playing with. And so this was just kind of experimental code, so we're not gonna worry about that, and we'll save it now. Okay, and so now you can see, this is fun, it's now appearing.

So that's nice, but then what if, say for example, you wanted to, let's see, let's look at todo viewer again. And inside of here we have this whole photo section, right? And what if we wanna actually let someone configure the image, right? Not only that, we wanna give them the ability to credit someone.

So let's say for example, we have an image, right? I know it got deleted, but earlier I think we had it public todo, right? So it was like this. So it was like todo.jpeg, and so we know that normally there's an all but, this is gonna get deleted shortly.

When you look at this, the problem is that if you try to configure this as props, what do you have to define? You have to define the image. You have to define the image alt, then you have to define the text photo by, and then, wait, if it's like a text, there's a lot of configuration that's gonna happen.

And so one of the problems that frequently occurs with a lot of frameworks is when it comes to props, people tend to over rely on it. And you get like prop drilling and a lot of things that tend to happen. And it feels like you're reading a dictionary by the time you're done using.

Do you need to like read documentation or to use a single component, and that's just a bit overkill. So, in view, something that we have is something called slots. And this is a very important concept. So if you think about it like this, if we were to like wrap this in a div, this is essentially let's go and just do that for like to wireframe it out.

This is a div with an id that's basically, let's call it hero. This is like the hero section, right? We have a photo with the credit of the image, and so what you ideally want is to make it easy for anyone to drop stuff inside of the hero div.

That's basically what you want to do. Well, using that exact same thinking cuz this is actually just normal HTML if you think about it, we use it all the time in the A-tag you drop stuff in it, in the div-tag you drop stuff in. Well, view has a built in, basically a built in component called slot.

And so I just self close it, because there's no point like this. Okay, and so the interesting thing about the slot, is that it basically says, hey, in this component, there's a section, and I want you to drop stuff in here. So to prove that this works, I'm gonna come in here, and inside of my component now normally they're self enclosed.

This is how we were used to seeing them. But if we treat them actually as normal HTML element, or like web components, there's been a lot of discussion about this recently. Now we can just drop stuff in here. So, I could really just be like, okay I'm just gonna drop an h2 to does this really work?

And then I'm also gonna drop that image right now just because I can, and I'll just say this is a source to slash todo.jpg, that's it and save. If you come over here, you'll notice it actually just gets slotted in. And it's funny because when I first saw this, it seemed like such a novel concept.

But again, we do this all the time in HTML. And so view opens up a way for you to automatically drop that in. And so what's cool with the slots then, however, is you're probably thinking like, okay, that's cool. But then like, what if I have other slots I wanna put in.

Let's say, we don't know what metrics we wanna display. Maybe we wanna change this part. So you might be like, okay, well, let me just comment this out for now. And you'll be like, okay, oops, I jumped too far. Yeah, I'm just gonna put another slot. Well, something should probably be occurring to you, as you see this is you now have two slots, and naturally, your compiler is gonna be like, which one do I use?

As well, don't worry, we have a solution for that. And the solution for that is that slots get names. So I could be like, well, the name of this slot will be metrics. And by default, the default slot is name is default, but I like to be more explicit just because it's a little bit cleaner.

And so we'll just call this section hero. And so you're probably thinking then, okay, well then how does this actually work? Well, the way this would work is you would actually wrap the HTML that you wanna put in there with a template. And so this gets a little like inception the bit because you're like wait isn't the template the outside part.

But it's like really a template, it's just a way to tell the compiler there's some HTML that I want you to group together. And so this template then gets to be passed what is called a V-slot. So basically, think of a v-directive, V-slot whatever, but this is saying that, hey, we know that we're gonna be using a v-slot.

And then you pass it an argument, which is the name of the slot. So in this one, I'm gonna add hero. And then I'm gonna add another template. And this V-slot is gonna go to metrics. And this time what I'm gonna do is I'm gonna say. This word save.

So now you'll see, well, this work showed up below the button just as you'd expect. And then does this really work with the image shows up at the top. But what might not be intuitive at first glance, though, is that it doesn't need to be in this order.

You can flip this, so if I flip the name of it, you'll notice it just, it puts it exactly where you want it to. Now, don't get me wrong, I would personally prefer to organize it the way it's probably intended to display. But just for the sake of understanding that it's possible, there's that.

Now just so you know, though the VSA does have a shorthand. So if you didn't know already, so V on, if you're like V on click. This can be short handed to an add symbol and we've already used the other one which I didn't get to explain at the time.

But V bind which I can attribute will make it a JavaScript, and so this would normally be short handed like this. Well, so the V slot which can to be clear it should only be used with this template element is not meant to be used with generic divs and stuff like that.

You can shorthand it to just the hash symbol. And so the way to think of it is like an ID is basically what you're doing there. It's really a preference thing I do see a lot of people using it because developers love shorthand. But I found that for people who aren't using slots as much it's a little bit confusing to see that because they're like it's just like a CSS.

Class ID is that like, so then googling, it becomes a little bit tricky. And so for me, I don't mind just being a little bit more explicit. But again, this is a preference and your team will figure it out. If everyone on the team knows what it is, no one's confused and by all means, feel free to use a shorthand.

But for what I'm teaching in particular, I always like to just write out the longhand for this in particular. So that no one's ever confused because then people can just literally Google V slot and then that will take them to the right place. As we know that the hash symbol has a lot of different meanings in programming so hence I like to try to avoid that whenever possible.

Okay so, the last thing I'm going to show you is that the interesting thing about slots, though, is that you can pass them props. And so if you haven't heard the concept of, it's typically called scope slots, but I prefer to call them slot props. Because what it's essentially doing is normally when you think of data, you think of the fact that the parent passes it to the child.

But you'll notice anything with a slot though is that you're allowing the parent to divine how something's being displayed inside the child. What if you could actually expose some of the data back into the slot that it's so we could rearrange it the way it wants to. So an example of this is let's say I'm gonna go ahead and say completed items.

I'll just say completed and this will be bound to complete a.items I'm sorry completed items just like that. What this does is when you go back into your app inside of this slot for metrics. What you can actually do is you get this slot props object. Now, it's not called slot props it's an object, but this is what I normally term it because that's basically what's happening.

And so just to show you what's in here we're going to do a pre on slot props. Okay, and what you'll notice is, in this particular case, completed is empty. But obviously if I go ahead and fetch that there's like a whole list of completed items. And so the thing about this atensil twist people up though, is that exposing your data from your child.

This stuff inside a slot is not actually exposed to the parent scope. It's just within the context of the slot, and that's the bends people's minds all the time, which is why I tried to approach it as slot props. It's a prop for the slot, not a prop for the parent, it's a prop for the slot.

So this way this is how if you look at some of the component libraries, this is how they let you actually configure how things are displayed. So like a multi-select, though, let's say that okay, well, you have these given options that in this select, you can rearrange it however your branding wants, put the icon on the left, put the icon on the right.

Whatever, but I've maintained the data in this child component. And now I've exposed it back to you so that you can now make it look pretty. But do not try to then go well I'm going to take this and put it in a method and my parent. I'm gonna do some funny stuff like that's shared state.

We need a cleaner way of doing that that's not what this is for. So now, for example, we could say in metrics is maybe in this particular case we wanna stay strong and then we can say like slot props.completed.length and then just this items completed. And now you can see zero items completed, but if I fetch the data, 90 items are completed.

And that's a really powerful thing that you can do now that you can expose this sort of like, again, it's almost like a little bit of a tunnel. But again, think of it more for display purposes and not for logic purposes. The moment you wanna like to share state and do that stuff, we'll come to that later on, I promise.

But for this thing of it as display. And so the other thing though, in case you don't like this slot props things because, again, developers we'd love shortening things. I do think this is an instance where slot props is a little bit overkill. And so you can actually D structure it to just say completed like this.

And then this will work exactly the same, and it's a little bit cleaner, but it does require that understanding that what you're destructuring is an object or props that are being passed at the child level. And so I think a lot of people when they see this for the first time, they're just like, what the heck is going on?

So that's why I always break it down this way. And once your team understands what's happening, it's actually quite a pretty clean syntax, because then you can map this one directly to the completed down here.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now