DEV Community

Cover image for 🎉Introducing Atomic Design in Vue.js🔥
Kittisak Ma for Vue PDF Viewer

Posted on • Edited on • Originally published at blog.vue-pdf-viewer.dev

🎉Introducing Atomic Design in Vue.js🔥

In my experience of building and delivering systems for various clients, depending on their requirements or preferences, it’s inevitable that I may use UI frameworks and libraries like Ant Design and Tailwind. Often, I have to build on top of each components. If you are working alone, it’s not such a big problem. But when working as a team, things get complicated quickly. So, I started looking at different methodologies which can provide development flexibility and system maintainability for the projects I’m leading. I choose Atomic Design methodology and want to share why it works for me.

Atomic Design Concept

Atomic Design is a methodology for creating design systems that breaks down user interfaces into small, reusable components, namely:

  1. Atoms
  2. Molecules
  3. Organisms
  4. Templates
  5. Pages

By following a modular approach to design, atomic design helps teams to create consistent, scalable, and maintainable UIs.

In this post, for simplicity, we'll explore how to implement Atomic Design in Vue.js with only HTML. I'll start with the basics of Atomic Design and then demonstrate how to apply its principles in Vue.js.

At the end of the article, you will get a page that consists of a header, a form and a footer. You can use the example here to apply to any UI framework.

Image atomic design with vue components

You may notice that each component has borders around it. This is intentional so you can identify whether it's an atom, a molecule, or an organism.

Vue-PDF-Viewer: A Versatile and Powerful PDF Solution for Vue.js

Here’s a little background on what I’ve been working on—Vue PDF Viewer. This library makes it easy to render PDF documents right within your Vue or Nuxt applications, allowing users to interact with PDFs directly on your site. With features like theme customization, built-in localization, and responsive design, it’s crafted to offer a flexible and seamless user experience tailored to your project’s needs.

Vue PDF Viewer

If you find this helpful, I’d love for you to check out Vue PDF Viewer. Your support inspires me to keep creating and improving tools for the developer community!

Anatomy of Atomic Design

Atomic Design consists of five levels that represent the building blocks of UIs. For this example, I have created an inverted tree structure to visualizing how each anatomy is connected.

- Page
 - Full Layout Template
  - Header Organism
    - Logo Atom
    - Search Form Molecule
      - TextBox Atom
      - Button Atom
  - Content Organsim
    - Form Molecule
      - 2x TextBox Atoms
      - Button Atom
  - Footer Organism
    - Copyright Atom
    - Subscribe Form Molecule
      - TextBox Atom
      - Button Atom
Enter fullscreen mode Exit fullscreen mode

1. Atoms

Atoms are the smallest units of UI that cannot be broken down further without losing their meaning. Examples of atoms include icons, buttons, labels, inputs, and typography.

In Vue.js, atoms can be created as reusable components that accept props to customize their appearance and behavior. For this instance, we have a few atoms to prepare for:

  • Textbox Image textBoxAtom
<template>
<div class="component-wrapper" data-name="textBoxAtom">
  <label>{{ label }}: <input type="text" :placeholder="placeHolder" /></label>
</div>
</template> 

<script>
export default { 
  name: 'TextBoxAtom', 
  props: { 
    label: {
      type: String,
      default: 'labelName'
    }, 
    placeHolder: String, 
  }, 
}; 
</script>
<style scoped>
  input{
      padding: 0.75em 2em;
  }
</style>
Enter fullscreen mode Exit fullscreen mode
  • Button Image buttonAtom
<template>
 <div class="component-wrapper" data-name="buttonAtom">
  <button :disabled="disabled"> 
    <slot>Button</slot>
  </button> 
 </div>
</template> 

<script>
export default { 
  name: 'ButtonAtom', 
  props: { 
    type: String, 
    size: String, 
    disabled: Boolean,
  },  
}; 
</script>
<style scoped>
button {
  color: #4fc08d;
}
button {
  background: none;
  border: solid 1px;
  border-radius: 2em;
  font: inherit;
  padding: 0.5em 2em;
}
</style>
Enter fullscreen mode Exit fullscreen mode
  • Logo Image logoAtom
<template>
  <div class="component-wrapper" data-name="logoAtom">
    <img :src="computedImageUrl" alt="logo"/>
  </div>
</template>

<script>
export default {
  props: {
    width: {
      type: Number,
      default: 50
    },
    height: {
      type: Number,
      default: 50
    }
  },
  computed: {
    computedImageUrl() {
      return `https://picsum.photos/${this.width}/${this.height}`
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

For a closer look, you can check out the codes in the Atoms collection.

2. Molecules

Molecules are combinations of two or more atoms that work together to perform a specific function. In Vue.js, molecules can be created by composing atoms as child components within a parent component. Examples of molecules include forms, search bars, navigation menus, and cards.

Referring to the example above, we will need to combine the atoms to create the following molecules:

  • Subscribe Form Molecule Image subscribeFormMolecule
<template>
  <form class="component-wrapper" data-name="subscribeFormMolecules">
    <TextboxAtom label="Email" />
    &nbsp;
    <ButtonAtom>Subscribe</ButtonAtom>
  </form>
</template>

<script>
import TextboxAtom from "https://codepen.io/9haroon/pen/LYXgdKg.js";
import ButtonAtom from "https://codepen.io/9haroon/pen/BaGqrJg.js";
export default {
  components: { ButtonAtom, TextboxAtom }
};
</script>
<style scoped>
form {
  display: inline-flex;
}
</style>
Enter fullscreen mode Exit fullscreen mode
  • Search Form Molecule Image searchFormMolecule
<template>
  <form class="component-wrapper" data-name="searchFormMolecules">
    <InputAtom label="Search" />
    <ButtonAtom>Search</ButtonAtom>
  </form>
</template>

<script>
import InputAtom from "https://codepen.io/9haroon/pen/LYXgdKg.js";
import ButtonAtom from "https://codepen.io/9haroon/pen/BaGqrJg.js";
export default {
  components: { ButtonAtom, InputAtom }
};
</script>
<style scoped>
form {
  display: inline-flex;
}
</style>

Enter fullscreen mode Exit fullscreen mode
  • Form Molecule Image formMolecule
<template>
  <div class="form-molecule component-wrapper" data-name="formMolecules">
    <div><InputAtom :label="nameLabel" :placeholder="namePlaceholder" /></div>
    <div><InputAtom :label="emailLabel" :placeholder="emailPlaceholder" /></div>
    <p>
      <ButtonAtom :disabled="isSubmitDisabled">
        {{ submitLabel || "Button" }}
      </ButtonAtom>
    </p>
  </div>
</template>

<script>
import InputAtom from "https://codepen.io/9haroon/pen/LYXgdKg.js";
import ButtonAtom from "https://codepen.io/9haroon/pen/BaGqrJg.js";
export default {
  name: "FormMolecule",
  components: {
    InputAtom,
    ButtonAtom
  },
  props: {
    nameLabel: String,
    namePlaceholder: String,
    emailLabel: String,
    emailPlaceholder: String,
    submitLabel: String,
    isSubmitDisabled: Boolean
  }
};
</script>

Enter fullscreen mode Exit fullscreen mode

You can find the codes in the Molecules collection.

3. Organisms

Organisms are combinations of molecules that form distinct sections of a UI, such as headers, footers, sidebars, and content blocks. In Vue.js, organisms can be created by composing molecules as child components within a layout component.

For this exercise, three organisms are needed.

  • Header Organism Image headerOrganism
<template>
  <header class="component-wrapper" data-name="headerOrganism">
    <LogoAtom width="60" />
    <SearchFormMoecules />
  </header>
</template>

<script>
import SearchFormMoecules from "https://codepen.io/9haroon/pen/zYMmjqa.js";
import LogoAtom from "https://codepen.io/9haroon/pen/xxQMbeJ.js";
export default {
  components: { SearchFormMoecules, LogoAtom }
};
</script>
<style scoped>
header {
  min-height: 50px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>

Enter fullscreen mode Exit fullscreen mode
  • Content Organism Image contentOrganism
<template>
  <div class="page-organism">
    <div class="content-wrapper-title">
      <h1><slot name="title">Here might be a page title</slot></h1>
      <p><slot name="description">Here might be a page description</slot></p>
    </div>
    <slot>...</slot>
    <!--   This might includes some molecules or atoms   -->
  </div>
</template>
<script>
export default {
  name: "ContentOrganism",
  components: {}
};
</script>
<style scoped>
.page-organism {
  padding-top: 50px;
  padding-bottom: 80px;
  box-shadow: inset 0px 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.content-wrapper-title {
  text-align: center;
}
</style>

Enter fullscreen mode Exit fullscreen mode
  • Footer Organism Image footerOrganism
<template>
  <footer class="component-wrapper" data-name="footerOrganism">
    <CopyrightAtom />
    <SubscribeFormMoecules />
  </footer>
</template>

<script>
import SubscribeFormMoecules from "https://codepen.io/9haroon/pen/ExOrarL.js";
import LogoAtom from "https://codepen.io/9haroon/pen/xxQMbeJ.js";
import CopyrightAtom from "https://codepen.io/9haroon/pen/gOQqOBj.js";
export default {
  components: { SubscribeFormMoecules, LogoAtom, CopyrightAtom }
};
</script>
<style scoped>
footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>

Enter fullscreen mode Exit fullscreen mode

Per usual, here's a collection of organisms' codes that I've created.

4. Templates

Templates are the structures that define the layout and composition of pages by specifying the placement and size of organisms within regions, such as headers, footers, and content areas.

In Vue.js, templates can be created as parent components that accept named slots for child components. Applying the 3 organisms to the Templates concept, here is how it could look like.

Image fullLayoutTemplate

<template>
  <div class="full-layout-template">
    <HeaderOrganism />
    <ContentOrganism class="content">
      <template #title>
        <slot name="title">default title</slot>
      </template>
      <template #description>
        <slot name="description">default description</slot>
      </template>
      <slot />
    </ContentOrganism>
    <FooterOrganism class="page-footer" />
  </div>
</template>
<script>
import HeaderOrganism from "https://codepen.io/9haroon/pen/WNYaJGR.js";
import ContentOrganism from "https://codepen.io/9haroon/pen/vYQbOeO.js";
import FooterOrganism from "https://codepen.io/9haroon/pen/RwqvPRN.js";
export default {
  name: "FullLayoutTemplate",
  components: {
    HeaderOrganism,
    ContentOrganism,
    FooterOrganism
  }
};
</script>
<style scoped>
.full-layout-template {
  display: flex;
  flex-direction: column;
  min-height: 90vh;
}
.content {
  flex: 1 0 auto;
}
.page-footer {
  flex-shrink: 0;
}
</style>

Enter fullscreen mode Exit fullscreen mode

here is the CodePen's link of the template

5. Pages

Pages are the final presentation of UIs that combine templates with specific content to form complete views. In Atomic Design, pages are like instances of templates that represent unique experiences for users.

In Vue.js, pages can be created by copying a template and replacing its slots with actual content. Although, in this example, I only change the content of Content Organism, you could choose to change all or no content.

Image homePage

<template>
  <FullLayoutTemplate>
    <template #title>{{ title }}</template>
    <template #description>{{ description }}</template>
    <div class="fixed-width">
      <FormMolecule nameLabel="Name" emailLabel="Email" submitLabel="Save" />
    </div>
  </FullLayoutTemplate>
</template>
<script>
import FullLayoutTemplate from "https://codepen.io/9haroon/pen/GRwzpxx.js";
import FormMolecule from "https://codepen.io/9haroon/pen/PoxyRMo.js";
export default {
  name: "HomePage",
  components: {
    FullLayoutTemplate,
    FormMolecule
  },
  data() {
    return {
      title: "Welcome to my example",
      description: "This is an example of Atomic Design in Vue.js",
      copyright: "Copyright © 2023"
    };
  }
};
</script>
<style scoped>
* {
  font-family: Avenir, Helvetica, Arial, sans-serif;
}
.fixed-width {
  max-width: 350px;
  margin: 0 auto;
}
</style>

Enter fullscreen mode Exit fullscreen mode

here is the CodePen's link of the page

Benefits of Atomic Design in Vue.js

By using Atomic Design in Vue.js, you can achieve several benefits, such as:

  • Consistency: By creating reusable components, you ensure that your UIs look and behave consistently across all pages.

  • Scalability: By breaking down UIs into small pieces, you can easily add, remove, or update components without affecting other parts of the system.

  • Maintainability: By organizing components into folders and files, you can easily find, edit, or debug them in isolation from other parts of the system.

  • Reusability: By creating standalone components, you can reuse them in other projects or share them with the community, thus saving time and effort.

Atomic Design is a powerful methodology that can help you design better UIs in Vue.js. By following its principles, you can create reusable, modular, and scalable components that make your code more maintainable and your users more satisfied. So, go ahead, give it a try, and let me know how it worked for you!

Vue PDF Viewer: A Complete PDF Solution for Vue.js

Vue PDF Viewer

If you’re looking for a powerful, flexible solution for rendering PDFs directly in your Vue or Nuxt applications, Vue PDF Viewer is the tool for you. Offering a wide array of features—like theme customization, localization support, and responsive layouts—it’s built to handle a range of project requirements while delivering a seamless, user-friendly experience.

If this sounds useful to you, feel free to explore Vue PDF Viewer and see how it can enhance your next project. It would mean the world and encourage me to create more content.

Thank you in advance! 🙏

Top comments (5)

Collapse
 
robinamirbahar profile image
Robina

Amazing Job

Collapse
 
9haroon profile image
Kittisak Ma

Thank you :)

Collapse
 
meerzulee profile image
Meerzulee

If I add a section, let's say "pricing section". Should it be considered as Template or Page or Organism?

Collapse
 
9haroon profile image
Kittisak Ma

Thank you for your comment and for engaging with the article.
In Atomic Design, the "Pricing Section" would typically be considered an "Organism".

Organisms are self-contained, complex UI components that can include smaller elements like "Molecules"(e.g., pricing cards, CTA buttons) and even "Atoms" (e.g., icons, text elements).
This approach helps maintain a modular and structured design system, making it easier to create consistent UIs.

I hope this clarifies how the "Pricing Section" fits into the Atomic Design methodology. Thank you again for your interest.

Collapse
 
d9k profile image
Dmitry • Edited

Three levels of organisation are often too little. Consider usage of more business-logic-oriented Feature-Sliced Design feature-sliced.design/docs/get-sta... app > processes > pages > widgets > features > entities > shared. Each level can only know about levels below and itself.