BairesDev
  1. Blog
  2. Software Development
  3. Streamline Your Design with Nuxt and Tailwind
Software Development

Streamline Your Design with Nuxt and Tailwind

Discover how combining Nuxt.js with Tailwind CSS can result in rapid, visually stunning web development.

BairesDev Editorial Team

By BairesDev Editorial Team

BairesDev is an award-winning nearshore software outsourcing company. Our 4,000+ engineers and specialists are well-versed in 100s of technologies.

17 min read

Featured image

In the evolving landscape of web design and development, efficiency, and aesthetics go hand in hand. With tools like Nuxt and Tailwind, you can achieve a seamless blend of both by leveraging the right CSS file structures. Welcome to our tutorial on ‘Streamline Your Design with Nuxt and Tailwind’. Whether you’re a seasoned developer familiar with the Nuxt community and Vue development services or a budding designer just starting to explore tailwind classes, this guide will walk you through the steps to integrate these powerful tools. Ensuring your websites are not only visually appealing with dynamic data attributes but also optimized for performance, you’ll be equipped to leverage the best of both worlds. Dive in and discover the synergy of Nuxt and Tailwind!

What is Nuxt.js?

Nuxt.js is a free and open-source framework built on top of Vue.js. It’s quite opinionated, especially when you compare it to React’s Next.js. This robust tool enables developers to install dependencies from its repository and build enterprise-level Vue.js applications with SSR (server-side rendering) capabilities. Nuxt.js comes with file-based template paths, code splitting, auto imports, data fetching utilities that are SSR compatible, TypeScript support, and build tools via Vite out of the box.

But what is server-side rendering and why is it good?

In layman’s terms, with frameworks like Nuxt.js and Next.js (for React developers), developers can write full-stack applications without creating a module online server via Node.js, Express.js, Nest.js, or any other language or framework. SSR enables us to write everything related to our applications inside the same codebase, same project. SSR is also quite good for SEO (search engine optimization), faster initial load time, way better performance with low-end devices, and easier caching.

What is Tailwind CSS?

Tailwind CSS is a highly popular CSS framework that helps developers write faster, more readable, and maintainable CSS code. With its unique tailwind config, customization becomes a breeze. While Nuxt.js already provides its own CSS section in the component, facilitating a smoother development server setup, integrating Tailwind CSS offers a different approach. It might seem daunting at first, but it greatly enhances developer productivity once they get past the initial learning curve.

In the following tutorial, we are going to create a Nuxt.Js project from scratch, add Tailwind CSS to it, and build a simple blog application. Instead of focusing on the logic, we are going to focus on how to use Nuxt.js and Tailwind CSS together.

How To Install Tailwind CSS & Nuxt.JS

To kick off the integration of Nuxt.js with Tailwind CSS, ensure you have all necessary repository install dependencies in place. Begin by installing Nuxt.js. After the installation, it’s crucial to check the peer dependencies. Once everything is set, you can then proceed to set up your dev server. Use the following terminal command to initialize your project:

npx nuxi@latest init <project-name>

Here, instead of project-name, you might want to write the name of your project, in our case, it is nuxt-tailwind.

After installation, we need to cd into that directory and run npm install or yarn to install the dependencies.

Then, we need to install Tailwind CSS to be able to use it with Nuxt.js. Now, the official documentation sometimes might cause problems. But the method we are going to follow is working perfectly at the time of writing. We are going to add Tailwind CSS as a Nuxt.js module. To do so, inside the directory, we’ve just created with nuxt CLI, we will enter this command on the terminal

yarn add -D @nuxtjs/tailwindcss@latest

Then, we will go to nuxt.config.ts file and change its contents with the following :

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ["@nuxtjs/tailwindcss"],
});

Then we will initiate Tailwind CSS by running `npx tailwindcss init`

Create The Main.CSS File

After that’s done also, we will create two new folders and a new main.css file and put the following code in it:

@tailwind base;
@tailwind components;
@tailwind utilities;

And this is the route of our newly created main.css file : ./assets/css/main.css

Now, if we were to run the application by yarn or npm run dev, we can try and test whether our installation was successful or not.

Test The Nuxt Tailwind Installation

To test it, we ca ngo to app.vue file and replace its contents with the following :

<template>
  <h1 class="text-3xl font-bold underline">
    Hello world!
  </h1>
</template>

Now if Tailwind CSS rules are applied, we should see this screen:

Building The Project: A Blog Website Named Jingles

The best way to learn is to practice. Now that we know what Nuxt.js is, what Tailwind CSS is and we’ve already set up and run our application, it is time to build something for it so that the knowledge would stick with us. Now, before starting, if you never used CSS in JS like Tailwind CSS before, the way how it approaches styling might seem confusing, even daunting at first. Here it is important to remember that we only move forward when we find ourselves in a not-so-familiar situation. So after this tutorial, Tailwind CSS should make sense to us, and we should be able to use it in our projects.

One last thing before we start, please do remember that when learning a CSS framework like Tailwind CSS, we are going to make heavy use of the official docs. We are not trying to memorize anything, because we don’t need to. The official docs are quite good and we can search for anything we want there easily.

Let’s get started by building the navbar for our application. Please keep in mind that for the sake of heuristic purposes, this application will not be mobile-responsive. We will only focus on the desktop version of it.

Building The NavBar

First things first: We will create a components folder, and insert a navbar.vue file inside it. Then, in our app.vue file, we will import it like this:

<template>
  <navbar />
</template>

<script>
import navbar from "./components/navbar.vue";
</script>

Now we can go back to navbar.vue and start writing code. In the template section, we are going to make use of flexbox to achieve our desired outcome.

Let’s add the following div:

<div class="flex justify-between items-center w-8/12 bg-[#d60068] p-5"></div>

In this div, we are doing the following:

-display flex

-justify content to space between so that the elements inside of it would be spaced to the opposite sides of the div

-align items to center

-make the width full width of the screen

-give it a background color of #d60068

-give it a padding of 5px from all sides

You see, this is how we write CSS via Tailwind CSS. If you already have been using Vue.js, then you’ll know that Vue.js comes with its own style section, where the developer can write CSS directly in the component. In CSS in JS, we don’t give class names to elements like divs, but instead, we write the desired CSS classes directly inside that element as a class name. Here, by writing flex and justify-center, we are telling Tailwind CSS to apply the display:flex and justify-content:center classes to this div. How do we know how to implement Tailwind CSS class and for what CSS class? By simply referring to the official docs.

Now there are a lot of classes there as usual. While developing, or reading code, we do not need to look for the element’s class name and then find the corresponding class tag to the class name and read the CSS from there. Instead, we are able to read it directly from the element itself. That is the beauty of CSS in JS.

We want to add four elements inside of this navbar, one of them aligned to the left and three of them to the right. We will again make use of flexbox, and create two divs. The first div will contain the element on the left, and the second div will take three more elements inside of it, to be aligned to the right with some space between them. As you can see, we are diving our visual plane into flex boxes. Now inside of the previous div, we add the following snippet:

    <div class="text-xl font-bold">Jingles</div>
      <div class="flex justify-around w-5/12">
        <router-link to="/">Home</router-link>
        <router-link to="/about">About</router-link>
        <router-link class="bg-black text-white p-2 rounded-2xl" to="/contact"
          >Contact</router-link
        >
      </div>
    </div>

What we are doing here is, with the first div, which is the element that will be aligned to the left, that has the text of Jingles, we are giving it a text size of xl, and a font weight of bold.

Then, we are creating another container div, that will contain the three elements to the right. In this container div, we are again initiating flexbox by writing flex, justifying the elements around so that they’ll have some space between them, and give it a width of 5/12 of the containing div.

Inside of it, we have three router-link items that we haven’t created yet, but will take us to their respective endpoints once we create them, and only give some styles to the last one by giving it a background color of black, a text color of white, a padding of 2px from all sides, and a border radius of 2xl (quite a lot).

And that’s it. We’ve successfully created the navbar of our application. Now, let’s go ahead and create the hero section.

Building The Hero Section

Now, as we’ve done with the navbar, we are going to create a hero.vue file inside of the components folder, and import it in our app.vue file.

<template>
  <navbar />
  <hero />
</template>

<script>
import navbar from "./components/navbar.vue";
import hero from "./components/hero.vue";
</script>

Then, we will go to hero.vue file and start writing code. Here, we want to have three elements on top of each other, and since this is the default behavior of the browser, we do not need to use flexbox here.Let us look at the following snippet:

<template>
  <div
    class="h-full w-full bg-[#d60068] py-5 pl-10 text-black border border-black"
  >
    <div class="text-7xl mb-5">Stay Hungry</div>
    <div class="text-2xl mb-5">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae,
      accusantium eos dolores quisquam porro doloremque culpa reprehenderit
      fugiat modi commodi numquam exercitationem id voluptas tempora. Ea
      molestias minus maxime velit.
    </div>
    <div>
      <button class="bg-black text-white p-2 rounded-2xl">Start reading</button>
    </div>
  </div>
</template>

What is going on here? First, on the container div, we are giving a height of full with h-full command. This full will not mean the full screen, if we wanted to have it take the whole screen, we’d say h-screen, instead, we are saying that is should contain the elements inside of it and expand accordingly. Then we have w-full, honestly, here we could just as well say w-screen and it wouldn’t change anything.

As we’ve done before, we give the background color with the bg command. Then we have py-5 and pl-10 commands. Those are related to padding. The first one means give it a padding of 5px from the y axis, that is, from top and bottom. And the second one says that give it a padding of 10px from the left. Then we give it a text color of black, and a border of black with a width of 1px. You see, it seems confusing at first. But the more you write Tailwind CSS, the more these classes are engraved into your mind and the faster, more productive you are.

Inside of that div, we have three elements: A title, a body text that is lorem ipsum, and a button that says start reading. For the title, we give a text of 7 xl and a margin bottom of 5 px with mb-5 command. We do a similar thing with the lorem text, but give it a 2xl font size. The button has a black background, white text, a padding of 2px from all sides, and is rounded.

And that’s it. We’ve succesfully created the hero section of our application. Now, let’s go ahead and create some articles for our app.

Building The Articles Section

We want to add at least four articles to our app. For that, we are going to make use of props because we do not want to write everything by hand. As it is said in software development, a rule of thumb is DRY (don’t repeat yourself) code.

Now let’s go ahead and create a new article.vue file in the components folder and add this snippet inside of it:

<!-- components/article.vue -->
<template>
  <div class="m-2 p-5 bg-black text-white">
    <div>
      <h2 class="text-xl font-bold">{{ title }}</h2>
      <p>{{ content }}</p>
    </div>
  </div>
</template>

<script>
  export default {
    props: {
      title: {
        type: String,
        required: true,
      },
      content: {
        type: String,
        required: true,
      },
    },
  };
</script>

<style></style>

Here we are creatng the model of the articles that we will display. By now you know that m means margin and p means padding, for background we write bg and by writing text-xl we’re giving the text larger font size. But we are doing something else too, something we haven’t done before, we are making use of the script section, that deals with javascript logic.

Here, what we are using is called options API in Vue.js terminology, there is also a newer composition API, but we are going to stick with the old, well-known options API for this tutorial. If you are a React developer looking to switch to Vue.js, then composition API might be more suitable for you, but if you are a beginner, then options API is also solid.

We are defining props, in props we have title and content. We give its types, and whether they’re required or not. And inside our template section, we are using the “mustache syntax” to display the title and content of the article. Mustache syntax is the double curly braces that you see in the template section. It is used to display data from the script section.

Now, let’s go ahead and import this component in our app.vue file, and use it to display some articles.

<template>
  <navbar />
  <hero />
  <div class="flex ">
    <div
      class="border border-l-amber-900 w-full"
      v-for="(article, index) in articles"
      :key="index"
    >
      <article :title="article.title" :content="article.content" />
    </div>
  </div>
</template>

<script>
  import Article from "~/components/article.vue";
  import navbar from "./components/navbar.vue";
  import hero from "./components/hero.vue";
  export default {
    components: {
      Article,
      navbar,
      hero,
    },
    data() {
      return {
        articles: [
          {
            id: 1,
            title: "Article 1",
            content: "Content of article 1...",
          },
          {
            id: 2,
            title: "Article 2",
            content: "Content of article 2...",
          },

          {
            id: 3,
            title: "Article 3",
            content: "Content of article 3...",
          },

          {
            id: 4,
            title: "Article 4",
            content: "Content of article 4...",
          },
        ],
      };
    },
  };
</script>

As you can see, we’ve added lots of things here. By now importing and using components are no secret to us. In addition to our general workflow, we have the data method in the options API, this data method deals with the data of the component. And we are doing that, we are creating an array of objects called articles, and adding the necessary things we want inside of it. We have the id, title and content. You might remember that in our article.vue file we were using title and content for display purposes.

Now, in the template section, under the hero component, we have two divs, and the Article component we import. The reason why we are creating two divs is that we want to make use of flexbox and instead of lining the articles on top of each other, we want to align them side by side, thus initiating the flexbox on the first container div.

Then, inside that div, we have another div that has the class tags of border, border color, and width of full. In Tailwind CSS, if we want to add a border to an element, we first need to initiate the border by giving the border keyword which is followed by how we want the border to be styled.

After that, we have a v-for keyword, that is Vue.js specific way of looping through elements. As you can see, it takes the article and index properties in the articles array of object, gives index as the key by :key=”index” command, and for each element inside the articles array of objects, it creates a new Article component. Here too, in order to pass the props, we need to define :title=”article.title” and the content in the same manner. Now, our application should look like this:

Conclusion

Concluding our Nuxt and Tailwind tutorial, this combo clearly provides an efficient and stylish solution for web design. In projects that demand high performance, streamlined designs, and SSR capabilities, a Nuxt app truly shines as an exemplary solution. However, for very simple websites or those without a focus on dynamic content, this might be an overkill.

While both Nuxt and Tailwind come with a learning curve, it’s a worthy investment. The modularity of Tailwind allows users to extend its functionalities with plugins and the flexibility of Nuxt offers vast opportunities to document and tailor web solutions with precision.

Considering the industry’s shift towards component-based architectures, many businesses now outsource Vue development. With the popularity of new frameworks such as Vue and utility-first design, there’s a compelling case that these tools will stay significant in the times ahead. By adopting them today, you position yourself at the forefront, primed to shape the upcoming wave of web innovations.

If you enjoyed this, be sure to check out our other web development articles.

FAQ

What are the primary benefits of integrating Tailwind CSS with a Nuxt app?

Integrating Tailwind CSS with a Nuxt app allows you to leverage streamlined utility-first styling, faster development cycles, and enhanced design consistency. And, with hired expert Vue developers, they can optimize the benefits of Nuxt’s server-side rendering for top-tier performance.

How does SSR (Server-Side Rendering) in Nuxt enhance web performance when combined with Tailwind’s utility-first design approach?

When Nuxt does its SSR magic, it makes pages pop up super fast and they’re SEO-friendly. But, did you know that while React SSR offers a similar benefit, Tailwind’s utility-first design kicks in to make styling a breeze? So, combining Nuxt’s speedy loading with Tailwind means your site not only looks sharp but runs like a champ. It’s like getting the best of both worlds!

Can I use existing Vue components in a Nuxt app with Tailwind, and are there any special considerations for styling?

Yes, you can use existing Vue components, including those from UI frameworks and component libraries, in a Nuxt app with Tailwind. However, ensure that Tailwind’s utility classes don’t conflict with existing component styles, and be consistent in applying your design approach throughout.

BairesDev Editorial Team

By BairesDev Editorial Team

Founded in 2009, BairesDev is the leading nearshore technology solutions company, with 4,000+ professionals in more than 50 countries, representing the top 1% of tech talent. The company's goal is to create lasting value throughout the entire digital transformation journey.

Stay up to dateBusiness, technology, and innovation insights.Written by experts. Delivered weekly.

Related articles

Software Development - My Experience With
Software Development

By BairesDev Editorial Team

6 min read

Software Development - Vue JS Routing:
Software Development

By BairesDev Editorial Team

15 min read

Contact BairesDev
By continuing to use this site, you agree to our cookie policy and privacy policy.