From JSX to Vue: my favorite templating tips
Tags: vue, beginners, javascript, bestpractices
Published: 2019-06-15 16:02:01

---
title: From JSX to Vue: my favorite templating tips
published: true
description: You might already know, but let's share it again!
tags: #vue, #beginners, #javascript, #bestpractices
cover_image: https://images.unsplash.com/photo-1526072339703-f3253bc87fdc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80
---

Coming from using JSX, I am amazed by the built-in templating features that Vue has. Since I'm one of the late adopters, these might not be new to you, but I wish I had known these perks when I started migrating to Vue. So, hopefully this helps people who are in the midst of migrating, trying out Vue, or maybe thinking of using Vue?

Anyway, here are some of my favorites.

## 1. `v-if`, `v-else` and `v-else-if` for conditional rendering

In the component, there would always be some conditions for the templates to be rendered. I learned that `v-if` can toggle elements to be rendered while supplying the condition. An example would be:

```html
<!-- Basket.vue -->
<section id="the-one-fruit-to-buy">
  <orange v-if="sourFruitSelected && isExpensive" />
  <grape v-if="sourFruitSelected && !isExpensive" />
  <apple v-if="!sourFruitSelected">
</section>
```

In this case, I only want to show one component at a time. If `sourFruitSelected` and `isExpensive` is true, `orange` would only be shown. Looking at the logic, this should look fine on browsers. But, if you look at the HTML, you would see something like this:

```html
<!-- Inspecting the HTML -->
<section id="the-one-fruit-to-buy">
  <div id="orange-component"></div>
  <!----->
  <!----->
</section>
```

Two elements are rendered with `<!----->` because the `v-if` statement is `false`. This is because every `v-if` is a single condition to the element it is targetting. Vue won't know that only one of the three elements is supposed to be shown if I'm using three `v-ifs`, which is three conditions to three different elements. Therefore, I should combine it with `v-else-if` and `v-else`:

```html
<!-- Basket.vue -->
<section id="the-one-fruit-to-buy">
  <orange v-if="sourFruitSelected && isExpensive" />
  <grape v-else-if="sourFruitSelected && !isExpensive" />
  <apple v-else>
</section>
```

This means it is just one condition to toggle three elements. In the HTML, it would look like this:

```html
<!-- Inspecting the HTML -->
<section id="the-one-fruit-to-buy">
  <div id="orange-component"></div>
</section>
```

But wait, there's more! While the conditional statement is valid, it can be hard to follow. How do we avoid `sourFruitSelected` and `isExpensive` logic repetitions? `<template>` tag can help you with that.

`v-if` is a directive, so it only works on a single element. If we put [`v-if` to a `<template>`](https://vuejs.org/v2/guide/conditional.html#Conditional-Groups-with-v-if-on-lt-template-gt) which is an empty wrapper of elements, we could improve the logic as follows:

```html
<section class="the-one-fruit-to-buy">
  <template v-if="sourFruitSelected">
    <grape v-if="isExpensive">
    <orange v-else />
  <template>
  <apple v-else>
</section>
```

## 2. `<component>` tag to avoid repetitions on similar components

Supposedly I was building a chart component with Vue that looked like this:

```html
<!-- Chart.vue -->
<chart
  :width="width"
  :height="height" />
```

Over time, I realized that I need more types of charts, built differently for each types, so the code now looks like this:

```html
<!-- Chart.vue -->
<pie-chart
  v-if="type === 'pie'"
  :width="width"
  :height="height" />
<bar-chart
  v-else-if="type === 'bar'"
  :width="width"
  :height="height" />
<column-chart
  v-else-if="type === 'column'"
  :width="width"
  :height="height" />
```

You noticed that there is some kind of pattern, right? With [`<component>`](https://vuejs.org/v2/api/#component) tag, I can improve the template as such:

```html
<!-- Chart.vue -->
<component
  :is="`${type}-chart`" 
  :width="width"
  :height="height" />
```

This basically means it will render a component that has `${type}-chart` as its name, defined under `:is`. Since all components share the same props (`width` and `height`), both will be passed down to each rendered components.

Do note that all the possible components have to be registered in the parent (or installed globally) in order for this to work.

## 3. `<slot>` tag for shared component reusability

Say I was implementing a modal component, and I would use it as such:

```html
<!-- Parent.vue -->
<modal :text="'Lorem ipsum'" />
```

The actual component would just be:

```html
<!-- Modal.vue -->
<div class="modal">
  {{ text }}
</div>
```

Then, I wanted to add actual HTML elements to the modal, like forms. Not just a simple text. How do I parse the string prop as HTML?

With `<slot>`, you can place any content from the parent down to the component's template. You shouldn't be using the prop anyway. So, the modal component template would be:


```html
<!-- Modal.vue -->
<div class="modal">
  <slot />
</div>
```

And the parent component that uses the modal would just be:

```html
<!-- Parent.vue -->
<modal>
  <form>
    <h3>Do you want to delete these files permanently?</h3>
    <button>Cancel</button>
    <button>Delete</button>
  </form>
</modal>
```

I think slots is one of the most interesting feature in Vue, taking component reusability to a whole new level. Be sure to check the [docs](https://vuejs.org/v2/guide/components-slots.html) for more in-depth details.

## 4. `.camel` prop modifier for specific camel-case HTML attributes

There are times when the HTML requires certain attributes to be written in camel case. Consider this example:

```html
<!-- Svg.vue -->
<svg :view-box="viewBox">
  <circle cx="0" cy="0" r="50"/>
</svg>
```

`viewBox` was written in kebab-case because [it is recommended for props by the styleguide](https://vuejs.org/v2/style-guide/#Prop-name-casing-strongly-recommended). I thought Vue would know and convert it back to camel case anyway.

Well, it won't! It will be rendered as-is. You have to specifically tell Vue that the attribute needs to be in camel case when rendered. You can fix that with [`.camel`](https://vuejs.org/v2/api/#v-bind):

```html
<!-- Svg.vue -->
<svg :view-box.camel="viewBox">
  <circle cx="0" cy="0" r="50"/>
</svg>
```

The `viewBox` will be rendered properly in the HTML.

## 5. `v-once` directive for cheap, static content in templates

Static contents that won't ever change can be optimized by adding `v-once` on the root of the content, so that it is only rendered once regardless. The [docs](https://vuejs.org/v2/guide/components-edge-cases.html#Cheap-Static-Components-with-v-once) says it all.

I think this is one of the least mentioned features in Vue, because I don't think static content has ever come as major performance bottlenecks among Vue users. But, if you're interested, you can use them and let me know how it goes. Or, if maybe anyone has gained any significant performance improvements with `v-once`, let me know as well, I would love to learn.

## Notable mentions

I'd like to also mention [`v-model`](https://vuejs.org/v2/guide/forms.html) which is a data communication model in-between parent and child, and [`<transition>`](https://vuejs.org/v2/guide/transitions.html) which is a built-in component for transitioning between elements, but I think each deserves its own article due to their robustnesses and the details to cover. Stay tuned!

---

Of course, I'm not saying JSX can't do what Vue does. I think with JSX, anything is possible, since it's just Javascript. The point of the article is more towards the ease of using Vue's built-ins to achieve what JSX can do (or better?). JSX has its own beauty, especially the type-checking, that I must say. In other news, you can still [use JSX with Vue](https://vuejs.org/v2/guide/render-function.html)!

By the way, if you have your own favorite Vue tips that aren't covered here, or if you have any feedback on the tips, do share it below in the comments. Also, these tips are already covered in their official docs, just thought I'd share with my own use cases.

Thank you for reading!

---

Cover image by [Jeffrey Hamilton](https://unsplash.com/@pistos?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/migrate?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText).