Fitting Slots Into Your Vue.js Code

At Phone2Action, one of the core technologies we use is Vue.js: a popular frontend framework for building user interfaces. An integral aspect of the framework, Vue components often turn large-scale modularization into a straightforward task. Unfortunately, this simplification comes at a cost; since the framework focuses on passing raw data from one component to another, sending formatted content via Vue’s slots can be a challenge.

That’s a shame, since you can use slots to clean up your codebase when:

  • Similar code is repeated in different components
  • Specific elements of a component are styled or formatted in different ways
  • Custom HTML is inserted in an existing component

For instance, let’s say we wanted to simulate a mailbox with Vue. There are two different types of mail: letters and packages. Each piece of mail needs an address and a stamp. The implementation might look something like this:

Now, you might notice that the code in letter.vue and package.vue is very similar. The only difference is in the contents section. A letter’s content is always on paper, but a package’s content varies. If we wanted to keep the convenient paper formatting in the letter, but not in the package, we’d most likely have to keep both in different components. This isn’t a good solution, because if we ever need to change anything about this shared code, we’d have to edit it in both letter.vue and package.vue. That’s a poor implementation, and opens up the door for many bugs in the future.

This is a perfect scenario for integrating slots. In the revision below, note the differences in total code length, the lack of redundant code, and the overall clarity:

We’ve created a new component, mail.vue, with all the repeated code between letter.vue and package.vue. The total code length is lower, since there’s no repeated code, and it’s a good deal cleaner as well. Hooray!

Most importantly, this mail component contains a brand new slot tag. When it’s referenced in the letter and package components, there’s something between the mail tags.

Think of slots as, well, slots. When there’s a slot, and the slot’s component is called, anything in between the slot component’s tags falls into the slot. Just as you can pass data from a parent component to a child using props, you can pass HTML content from a parent to a child using slots.

Here, the parent component, the letter (or package) passes its contents into a child mail component, and the contents are customized based off the component they’re passed from. Not bad.

What if we wanted to format the different types of mail some more? Could we do that as well?

Of course we could, and we’d use slots for that as well:

Just like we did with the mail component, we added a slot to both the letter and package components. Now, when we want to make a letter look nice, we format some fancy HTML that we put between the letter’s tags. Vue works its magic, and this HTML appears where the letter’s slot used to be.

It’s also possible to use multiple slots in one file, and this is useful if we want to insert HTML into multiple different places in the component. Let’s say we decide that each letter will have a heading, in addition to its usual content. We can accomplish this using named slots:

Since we’re changing multiple different parts using multiple different slots, Vue needs to know what to put where. This is done by naming slots.

Inside the letter tags, we insert the heading by making an element with the slot=”heading” attribute, after a slot with name=”heading” has been defined in letter.vue. As you may have guessed, anything inside the slot=”heading” element goes into the name=”heading” slot. Anything else inside the letter tag will move into the default slot, which doesn’t need a name.

In short, slots add another dynamic layer to a Vue component. Here at Phone2Action, they help us consolidate and standardize code across components, while also allowing a great deal of component-specific customization. A good understanding of slots and named slots helps you write cleaner code and adds yet another tool to your Vue toolbox.

About the author

Liam is a 2017–18 Civic Technology Fellow. He is a rising senior at Thomas Jefferson High School for Science and Technology in Alexandria, Va. He joined Phone2Action last summer after winning his fellowship at a hackathon, and has stayed ever since. Sticking to his programming roots, Liam still competes in hackathons with his friends when possible.

Learn more about our Civic Technology Fellowship program.