Skip to main content

8 Vue.js Slots with Tailwind CSS and Rails

Episode 242 · May 2, 2018

Learn how to use Vue.js slots to make even more reusable components. In this episode, we build a dropdown menu for Tailwind CSS apps using Vue.js slots.

Javascript Frontend css Vue.js


Transcripts

What's up guys? This episode we're diving into Vue.js again, this time we're talking about a feature of Vue called Slots. Probably haven't heard of this before, it's not super common, but it's really really handy and I want to show you how to use it in this episode. Now TailWind CSS is just a CSS only library, it doesn't provide you any JavaScript nicities like Bootstrap does with dropdowns and tabs and other things like that, so you have to build those things yourself so your navigations like these simple links here or a header aren't able to have JavaScript to toggle dropdown, so what we're going to be doing is building a Vue.js component that is generic. That component will be able to be used anywhere in your application and will be able to drop in dropdown menus pretty much anywhere. So let's dive into implementing that.

So I've got a rails application here with a Vue and of course TailWind installed, so we're going to use this as our example, and we're going to implement dropdowns in both of these navigations just so you can see how those work, so let's dive into our code. Now we're going to need to define this component somewhere, so I'm going to make a directory called app/javascript/components and we're going to create a file in there app/javascript/dropdown.vue, so this file is going to have a standard template, and it's going to have our script for it, and the script really only has to do one thing, so we're going to have our

<template>
</template>

<script>
export default {
  data(){
    return {
      open: false,
    }
  }
}
</script>

We're going to have this as the only real value that a dropdown needs to keep track of, which of course is really the only thing it needs is the memory of whether or not it's open, and so that's pretty straight forward. Now what we're going to do here is define our dropdown as a whole, so this will be kind of a generic idea of a dropdown. Really a dropdown has the button or whatever the link is that you click, and then it has a whole separate section for the visible set of links that are displayed when it's open so we're gonna have these two sections that we need to have and then we will be able to customize both of those using slots. What we need is basically a div here that's class relative and tailwind classes so if you aren't familiar with these take a look at tailwind but we're going to define all of this in tailwind designs, so then we're going to have a div, the button role for this isn't required but it is helpful to note that this is actually the button that we will be clicking on, and then we'll have a little bit of class styling for this it will be inline block

<template>
  <div class="relative inline inline-block">

    <div role="button" class="inline-block select-none" @click.prevent="open = !open">

    </div>
  </div>

</template>

That's it for this div, and that will be the place inside of it we want to put in a link maybe or something like that to actually have this toggleable. Inside here we'll create a slot and we'll give it a name and so this name will be say the link that we would display and then that slot will just be empty, and then underneath it we can define the links for the visible version of the dropdown, so we'll have

<template>
  <div class="relative inline inline-block">

    <div role="button" class="inline-block select-none" @click.prevent="open = !open">
      <slot name="link"></slot>
    </div>

    <div v-show="open">
      <slot name="dropdown-items"></slot>
    </div>
  </div>

</template>

These are basically just these places where the parent can say hey, we're gonna pass in these props but you won't have to pass them in actually as props, they can go inside of the tag and in the parent, so we'll show you how that works, but basically these are going to work just like props, except that they are defined inside of the template instead of passed in as props, so let's finish up a little bit of the styling here we're going to have absolute on this and then we're going to pin it to the right, then we'll have it 32 wide, margin of the top of 2 and we're gonna change the Z and X to 10 so it should show up on whatever content it will be hovering over. That is how our template will look, and really we'll have these two main sections, the button and then the visible open version of it, so we've given it nothing too special, but all of this stuff is extremely customizable once we get into implementing this, so let's go to our navbar partial and start adding our navigation headers, so for example maybe in the blog link here we want that to be changed to say features and then it's maybe a drop down of the features or whatever that you might want to put in your navigation, so we will go modify this one and add the drop down link to it

<div v-show="open" class="absolute pin-r mt-2 z-10">

But first we're going to need to go into our application.js and register that component for the dropdown, so we're gonna have to

import Dropdown from '.../components/dropdown'
Vue.component('dropdown', Dropdown)

So anytime that drop down is referenced as an html here so say <dropdown> then that is going to load up the Vue component inside of our application and the reason all this works of course is because in our application.html.erb layout we have this data behavior view wrapping all of the content on the page and that is of course referenced here when we create our new view app so that means we can use Vue components absolutely anywhere in our rails layouts and that will automatically be wired up and we can pass in json to those really easily and so you can have a lot of flexiblility and nice integration between rails and views.

I'll have a link to the previous episode where I talk about how this works if you're not familiar with that, but let's dive back in to implementing our slots. Now it's as simple as saying: slots="link" here in our anchor tag if we change this to say like features instead of blog, we can have that actually go through and replace the link in our component, so this is basically giving it a little overrides that aren't props where you wouldn't say link=<a href bla bla bla, that would not be great so they give you this ability to pass in slots and then have any arbitrary amount of text in there. That is really cool and then you can use any type of tag as well so for the dropdown items we're going to put in a div and we're just gonna say the text of hello.

In the browser, if we refresh the page, we can see that this hello shows up underneath features and toggles everytime we click on it, and that is really cool, and also we have full control over the dropdown's appearance inside of our dropdown here, so we can design this drop down to look totally different from another drop down, but they'll still have the exact same functionality, so that is really cool so this allows us to then go into say our hello section here and we could just use rails links and say: Well maybe this feature of a blog is part of it, and we can add a class and we can add some items to that for the styling, so we don't want an underline, we want our links to be blocks, we wanted some padding, border on the bottoms, some text coloring, and backgrounds, and then when you hover over it we want to change the color from white in the background to blue in the background, so that will be pretty simple, and then we can also define some classes on our drop down itself so this will actually look like more of a drop down, so let me grab some classes for that. We're going to have background of white, we want a shadow on it, we want it to be rounded, we want a border around it and we want overflow hidden as well, so if we do that, and we refresh our page, we should see now that when you click this, it looks much more like a real dropdown, so that is very awesome.

We can click those and navigate away and that will work like we would expect. This is cool, we can add in as many links as we want and they will just automatically fill out inside of that dropdown, the other neat part is because we can fully define these slots however we would like, is that we can then go define them in any other location. In our index on posts, we have this little navigation here that I copied from the repo as well, so if we wanted to implement a drop down on one of these, we could go, define drop down here, we could say this is slot for the link, this div here will be slot for dropdown items, and we'll have a closing div tag there and maybe we grab you know a similar looking blog item here, and on this one we'll define some classes like background, weight, we'll have the shadow, but it won't be rounded and we'll have a border and oveflow hidden, and so in this case we will now be able to click this link and see a not rounded version of it, but this one is rounded and that will be the different ones, and each one of these will toggle separate from each other, which is really cool, so they're running independentely as different components and we can define the styles of these entirely how we would like. If you wanted to make these styles always the same you could extract that class for the background and everything and put it inside of the dropdown component or you could make that like a prop or something that you pass in the style that you would want. That is kind of cool, and very very flexible.

I also really like that if we wanted to add like the caret to show that it's a dropdown only on this one navigation item, we can go in and paste like an SVG or an icon for that and just drop it in and now voilà, our navigation has a caret showing that this is a dropdown menu, and of course you need to do some other styling to make it blend in properly and be aligned correctly and all that stuff, but you have absolutely full control over that because those slots that you've defined are fully replaceable and so you're just dropping that stuff into the relevant portion and your dropdown just needs to know that one section of this is going to act like a button, and we're going to put a wrapper div around that, that you can fill out the contents however you like, and then our dropdown really just needs to be absolute and pinned in a certain location, but now what I've done is I've set a width of 32 up here, but you can actually go set that inside of your components here in the dropdown item slot, and so that would allow you to define multiple widths, you can even change the pin as well if you wanted to pin it to the left side instead of the right side it's entirely up to you and you have a lot of functionality that you can take advantage from that. What's really neat about his is that this is very very similar to your layouts where you have yield blocks, if you've ever done something like up in the header you might have had yield head and then later on in another template you might have <%= content_for :head, "TEcoeisfo" %> and that would actually be inserted into the head inside of your layout. That is the exact same type of functionality that you're getting here with Vue.js slots, so what I love about this is that number one you probably already know how this is going to work because you're familiar with yield and content_for in rails, and then number tow is these components are very very simple, and you can use them and drop them into any applications and they don't control any of your styling, all of that is up to you and how you implement it. For the most part we had to do a little bit of relative and absolute positioning but of course every dropdown has to do that, so keep that in mind of course but for the most part this is very generic from every other piece of styling like shadows and borders and backgrounds and all that stuff, it's entirely up to whoever implements the dropdown. This is cool and I can imagine building up a suite of these to just implement with your TailWind application so you have things like tabs, dropdowns, modals, you know all those different little features that Bootstrap comes with we could have very generic versions of those in Vue.js that you could just implement in an import statement and have all of that ready to go.

Hopefully, we'll build out some more of these in the future and have that JavaScript functionality already ready for anybody interested in using this with TailWind CSS.

Transcript written by Miguel

Discussion


Login or create an account to join the conversation.