Structuring Vue Components

As soon as you start learning Vue you find out that the atomic unit of its architecture are components. In fact, that’s nothing Vue-specific: any component-based technology, such as React or Angular, work the same way.

Then you learn more about components and how to build them. You start creating your own components, combining them and applying different communication patterns in order to build more complex components. Sure you’re doing great and keep the components as small as possible so you can reuse some of them in several places of your application.

But at some point, the application grows. You have many components and things are starting to get messy: it’s hard to find the right component and to know its responsibility, then maintainability starts to suffer.

No worries, in this article we’re going to see different ways and tips you can use to structure your application components.

First Steps: Pages

A basic structure commonly seen when starting an application from scratch has a components folder, along with a main.js entry file and an App.vue component:

src/
        main.js
        App.vue
        components/

After a while, you’ll have several components. A very simple example of that structure, could be:

components/
        ArticlePage.vue
        ArticleTitle.vue
        ArticleList.vue
        AppButton.vue
        AppFooter.vue
        AppHeader.vue
        LastArticlesSection.vue
        AppList.vue
        UserPage.vue

Note: Vue’s style guide multi-word rule tells us not to use a single word to name a component, that’s why we’re prefixing some with “App”

In component-based technologies, everything is a component. Having a fact like that, we must think about a way to categorize them.

If you take a look at above’s structure, you can easily identify one type of components: pages. Thus, we can create a pages folder when we can place our page components:

components/
        ArticleTitle.vue
        ArticleList.vue
        AppButton.vue
        AppFooter.vue
        AppHeader.vue
        LastArticlesSection.vue
        AppList.vue
pages/
        ArticlePage.vue
        UserPage.vue

That’s an easy split and already gives us a bit of structure, so that when we know where to place and search for pages components.

However, a page is usually composed by more components or sections. Related to the ArticlePage, we see the ArticleTitle, ArticleList and LastArticlesSection components.

Let’s assume ArticleTitle and LastArticlesSection are meant to exist only in the ArticlePage, but ArticleList is a component that fetches and renders a list of articles, and it can be used in multiple places.

Master Vue.js with Vue School

Top notch Vue.js courses and over 200 lessons for just $12 per month!

Given these facts, it would make sense that ArticleTitle and LastArticlesSection are placed along with its page in a common folder:

components/
        ArticleList.vue
        AppButton.vue
        AppFooter.vue
        AppHeader.vue
        AppList.vue
pages/
        ArticlePage/
                index.vue
                ArticleTitle.vue
                LastArticlesSection.vue
        UserPage.vue

We’ve also renamed ArticlePage.vue to index.vue. Thanks to how module resolution works, when we import the article page in this way:

import ArticlePage from "@/pages/ArticlePage"

It will be imported it from pages/ArticlePage.vue or pages/ArticlePage/index.vue. For that reason, we can always start creating the pages as a component and later move it to a folder without having to change the way to import it, making refactoring easier.

Common components

We still have components with mixed responsibilities and domains in the components folder.

There is another split point on UI components: those that are reusable across the whole app. They communicate just by using props and events, not holding any application logic.

In the structure of this example, we see that the AppButton and AppList components are one of them, so let’s place them under the ui folder:

components/
        ui/
                AppButton.vue
                AppList.vue
        ArticleList.vue
        AppFooter.vue
        AppHeader.vue
pages/
        ArticlePage/
                index.vue
                ArticleTitle.vue
                LastArticlesSection.vue
        UserPage.vue

The AppFooter and AppHeader components, however, are not exactly UI components. Instead they’re more like layout components since the app will have only one footer and header. You don’t need to, but you can move them to a layout folder if you want:

components/
        layout/
                AppFooter.vue
                AppHeader.vue                
        ui/
                AppButton.vue
                AppList.vue
        ArticleList.vue
pages/
        ArticlePage/
                index.vue
                ArticleTitle.vue
                LastArticlesSection.vue
        UserPage.vue

What about the ArticleList component? We can have components that are reusable in different pages, so we shouldn’t place them with the page components. However, they belong to a specific domain, in this case to the article domain.

Let’s call them domain components. A good way to organize them is to place them in separate folders under components, one folder per domain:

components/
        article/
                AppList.vue
        layout/
                AppFooter.vue
                AppHeader.vue                
        ui/
                AppButton.vue
                AppList.vue
pages/
        ArticlePAge/
                index.vue
                ArticleTitle.vue
                LastArticlesSection.vue
        UserPage.vue

Again, we can remove the Article prefix since the path is already representative. In fact, now we have two List components:

import ArticleList from "@/components/article/List"
import AppList from "@/components/ui/AppList"

Lastly, what about the rest of the components? There can be components that belong to no domain, are not ui or layout. They can be some kind of utility components that have some logic but delegate the rendering to children components.

For example, imagine an Observer component that detects when its children intersect on the screen. Another example is vue-no-ssr: a component that renders its children only when it’s running on the client, in case you’re applying Server-Side Rendering (SSR) or you’re using Nuxt.

We can place this kind of uncategorised common components under a common folder:

components/
        article/
                AppList.vue
        common/
                AppObserver.vue
                NoSSR.vue
        layout/
                AppFooter.vue
                AppHeader.vue                
        ui/
                AppButton.vue
                AppList.vue
pages/
        ArticlePage/
                index.vue
                ArticleTitle.vue
                LastArticlesSection.vue
        UserPage.vue

Wrapping Up

We’ve seen different techniques to structure your application components. They might be helpful for you or not, but I hope at least you got some ideas that you can use from now on.

Master Vue.js with Vue School

Top notch Vue.js courses and over 200 lessons for just $12 per month!


Article written by Alex Jover Morales

Passionate web developer. Author of Test Vue.js components with Jest on Leanpub. I co-organize Alicante Frontend. Interested in web performance, PWA, the human side of code and wellness. Cat lover, sports practitioner and good friend of his friends. His bike goes with him.