Summary
In this guide, you will add Tailwind to a Vue application to improve the layout for our blog pages. You will go through dependencies, configuration, and component creation. To follow this tutorial you will need a basic understanding of Vue.
Why use TailwindCSS?
In 2019‚ and even more so in 2020, Tailwind CSS exploded in popularity when developers saw the potential in a design system that was more like an API. Unlike Bootstrap, which provides pre-built components, Tailwind CSS provides utility classes to build your own components that are completely responsive and let developers create exactly what they need. Tailwind and Vue integrate together with just a few packages, making it a go-to option for any developer.
What are utility classes?
Utility classes are single purpose classes which are self descriptive in nature, unlike traditional CSS classes. For example:
.flex: {
display: flex
}
This example describes that you are adding flex, and only adds display flex to an element. This makes it reusable anywhere in the code and know exactly what it does.
Finished project link
To follow along exactly with the blog post you can find the repository on my GitHub by clicking this
link.
Setup
Add the dependencies
To begin with, you need to install the dependencies for Tailwind. Inside your terminal or command prompt, from the root of your project, type the following:
npm install tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
First, you are probably wondering why you are versioning, well there is (as of April 2021) a compatibility issue between tailwindcss
and postcss
which you can read about here. So what do these dependencies do? Let's break them down:
tailwindcss : Contains all the Tailwind code that you can use in our Vue application.
postcss : PostCSS is used to transform CSS using a variety of JS plugins, it's a one stop-shop for being able to lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.
autoprefixer : AutoPrefixer is a plugin for postCSS that parses all of your CSS and adds the vendor prefixes to your CSS rules. This means you don't have to worry whether you are using Microsoft Edge , Firefox, or Chrome!
Creating Tailwind configuration files
Now you have all of the dependencies installed you need to create two configuration files that will handle both what happens with PostCSS and any configuration you want to make with Tailwind such as themes, dark mode etc. At the root of your project create a tailwind.config.js
and postcss.config.js
and let's take a deep dive into what you have, first let's open the newly created tailwind.config.js
file and create our default configuration:
// ./tailwind.config.js
module.exports = {
purge: [],
darkMode: false,
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
Tailwind is built on the premise of building customized user interfaces from the ground up, in this file you can create a whole theme, use plugins, set default colors and so much more. In this tutorial, you will be using the purge option only. The purge option allows you to put in all of your files that contain CSS and as part of the build step will removed any used styles. You can learn more about configuring Tailwind in the configuration documentation. Let's move on to the postcss.config.js
file and enter the following :
// ./postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
As mentioned earlier, you use PostCSS to transform CSS using a variety of JS plugins, in this case when our code is built PostCSS will handle both Tailwind CSS and any prefixes for browsers without any intervention from us!
Configure Tailwind to remove any unused styles in production
The final piece of our configuration is to have Tailwind purge any unused styles when in production to keep our bundle size as small as possible, to do this open up your tailwind.config.js
file and type the following:
// ./tailwind.config.js
module.exports = {
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
darkMode: false,
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
What you are doing here is telling Tailwind where the paths to all our components and pages so Tailwind can remove all unused styles using a technique called tree-shaking, which deletes all the unused styles.
Adding Tailwind to our CSS
Now that you have installed and set up everything required to start using Tailwind you need to create a way to use it globally. So let's create an index.css
in your src
folder to hold our Tailwind styles:
<!-- ./src/main.css -->
@tailwind base;
@tailwind components;
@tailwind utilities;
This might seem like you are going to have every single Tailwind style in our application but at build time Tailwind is smart enough to styles generated based upon your configuration.
Import your CSS file into main.js
The final setup piece is to import the CSS file into our main.js
which is located at ./src/main.js
and once imported your file should look like:
// ./src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
createApp(App).mount('#app')
Tailwind is now set up and referenced, so you are ready to create a great looking blog page.
If you are following along here is the commit
Creating Components
For this tutorial, you are going to create a navigation bar and a blog page which will be our home page, the blog posts won't actually exist but it will give you a great starting point for your own blog post.
Creating a Navigation Bar.
Let's begin by creating a responsive navigation header that you can use on each page. Let's have create some starter code that doesn't have any Tailwind attached, create a new component called NavBar
:
<!--./src/components/NavBar.vue -->
<template>
<header>
<div>
<nav>
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/">Blog</router-link></li>
<li><router-link to="about">About</router-link></li>
</ul>
</nav>
</div>
</header>
</template>
<script>
export default {
name: "NavBar",
};
</script>
Now you have this new NavBar
component let's use it in our application by adding it to our App.vue
file. Inside the App.vue
file remove the original div
above the router-view
below is the before and after:
<!-- ./src/App.vue -->
<!--before -->
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<!-- after -->
<template>
<div id="app">
<router-view />
</div>
</template>
You are now ready to place use our own NavBar
component. To import a Component you need to add a script
tag under our template and then register the template copy the code below :
// ./src/App.vue
...
<script type="text/javascript">
import NavBar from "@/components/NavBar.vue";
export default {
components: {
NavBar, // register component
},
};
</script>
Then you can add this into our template, so before the router-view
add in the NavBar
so your finished code should look like the following:
// ./src/App.vue
<template>
<div id="app">
<NavBar />
<router-view />
</div>
</template>
<script type="text/javascript">
import NavBar from "@/components/NavBar.vue";
export default {
components: {
NavBar, // register component
},
};
</script>
Now launch your code and navigate to localhost:8080
and you should see the following:
It doesn't look great but the links to Home
and About
work as expected so let's add some Tailwind to this to make a navigation bar with responsiveness!
Adding Tailwind to our component
Open up your NavBar
component and let's start adding some classes from Tailwind, first you want to add a border to the bottom to add some division, and then you will add some flex to our surrounding div
:
// ./src/components/NavBar.vue
<template>
<header class="border-b">
<div
class="container flex flex-col flex-wrap p-5 md:items-center md:flex-row"
>
....
So let's explain what is happening here,
- Under the header, you are adding a
class="border-b"
which is a border on the bottom. - Then in the
div
you are adding thecontainer
class. - Adding
flex
and any screen, bigger than medium size will beflex-col
withflex wrap
. - Adding
p-5
which addspadding: 1.25rem
The part md:items-center md:flex-row
means when the size reduces to a breakpoint for medium screens, it will center the items and make them into a row. You can read about responsive designs and conditional breakpoints in the link below:
https://tailwindcss.com/docs/responsive-design
Next, you can add flex
to our <ul>
and some margin and font styles to our links to make sure you have a functional and responsive Navbar.
// ./src/components/NavBar.vue
<ul class="flex flex-wrap items-center justify-center text-base ">
<li class="mr-5 text-sm font-semibold hover:text-gray-800">
<router-link to="/">Home</router-link>
</li>
So this code, allows the items to wrap as needed, and on the individual items you are adding a margin on the right, making the font bold and changing the state when you hover over them, at this point your code should look like the following:
// ./src/components/NavBar.vue
<template>
<header class="border-b">
<div
class="container flex flex-col flex-wrap p-5 md:items-center md:flex-row "
>
<nav>
<ul class="flex flex-wrap items-center justify-center text-base ">
<li class="mr-5 text-sm font-semibold hover:text-gray-800">
<router-link to="/">Home</router-link>
</li>
<li class="mr-5 text-sm font-semibold hover:text-gray-800">
<router-link to="/">Blog</router-link>
</li>
<li class="mr-5 text-sm font-semibold hover:text-gray-800">
<router-link to="about">About</router-link>
</li>
</ul>
</nav>
</div>
</header>
</template>
<script>
export default {
name: "NavBar",
};
</script>
If you are following along here is the commit.
You should now have a navbar that looks like this on your desktop:
Then when you shrink the screen size down and hit the media point you should now have a navbar that looks like:
Looking pretty good! A nice NavBar
component to help our users navigate our website.
Creating the blog post page
As I explained previously, you aren't creating any blog posts but you can create a "fake" Blog page that will show the user a cover image, title, and excerpt. To make this easier below is the code will be using but first let's create a new component called BlogPage
which will handle that in our components directory.
<!-- ./src/components/BlogPage.vue -->
<template>
<div id="blog-home">
<h1>Thoughts and Posts</h1>
<div>
<article>
<figure>
<img src="http://via.placeholder.com/250x250" alt="" />
</figure>
<h2>A blog post about my dog</h2>
<p>Super awesome doggo, with a great smile.</p>
</article>
</div>
<div>
<article class="media">
<figure>
<img src="http://via.placeholder.com/250x250" alt="" />
</figure>
<h2>Post about some code we wrote</h2>
<p>Sometimes coding is very hard, and othertimes it's very easy</p>
</article>
</div>
<div>
<article class="media">
<figure>
<img src="http://via.placeholder.com/250x250" alt="" />
</figure>
<h2>Titles are hard to think of.</h2>
<p>Just like naming variables, naming title are hard.</p>
</article>
</div>
</div>
</template>
This has three basic blog posts with a title, image holder and a short excerpt, you now have a component
but you need to create a route
and view
so our users can navigate. Create a new file inside your views folder called Blog.vue
, this will handle what is displayed to the user when they navigate to the route.
The view template will be simple because you created a component
and don't have to worry about creating any more HTML
so below is the template part
<!-- ./src/views/Blog.vue-->
<template>
<div class="blog">
<BlogPage />
</div>
</template>
Similar to App.vue
you are registering the component to use it. Now you need to add a route to our routes file, which is located under router
named index.js
. To add the router you can copy the about route.
Now you need to import the BlogPage
component and reference it so you can actually use it in our view.
<!-- ./src/views/Blog.vue-->
...
<script>
import BlogPage from "@/components/BlogPage.vue";
export default {
name: "Blog",
components: {
BlogPage,
},
};
</script>
<!-- ./src/router/index.js -->
{
path: "/blog",
name: "Blog",
component: () => import(/* webpackChunkName: "blog" */ "../views/Blog.vue"),
},
If you are following along you can check out this commit.
Go ahead and launch your application and navigate to http://locahost:8080/blog
and you should now see the following:
This is not pretty or responsive, so let's start adding our Tailwind to make a blog post page look great!
Adding Tailwind to the blog post.
So you are going to create a grid style blog page where each post takes up 1/3 of the width of the screen. To begin with let's center our Heading and increase the size and add a margin to the top:
<!--./src/components/BlogPage.vue-->
<template>
<div id="blog-home">
<h1 class="text-center text-xl mt-4">Thoughts and Posts</h1>
...
This will give our heading a nice centered look and increase the size.
Now you can create a container using the next main
and add some padding around the top and sides.
<!--./src/components/BlogPage.vue-->
<template>
<div id="blog">
<h1 class="text-center text-xl mt-4">Thoughts and Posts</h1>
<main class="container px-8 pt-24 mx-auto lg:px-4">
.....
This gives us the container class padding on the sides and top, margin on the x-axis to auto and on large screens, you will also at padding on the x-axis.
You now need to add an additional div
surrounding our article, which will handle flex for us. So create a new div
and add the classes flex flex-wrap
.
<!--./src/components/BlogPage.vue-->
<template>
<div id="blog">
<h1 class="text-center text-xl mt-4">Thoughts and Posts</h1>
<main class="container px-8 pt-24 mx-auto lg:px-4">
<div class="flex flex-wrap">
....
Now you have our container, and flex div
you can start working on our articles, now in the real world, you would only need to create a single one and loop over all of your articles. So I will show you how to create a single version of it, and then I will show you a complete version.
On our article
tag let's add the classes for padding, and width for both large screens and the default sizing.
<!--./src/components/BlogPage.vue-->
<article class="px-8 py-6 lg:w-1/3 md:w-full">
This will add padding on the sides and top and bottom, on a large screen it will take 1/3 of the width and on smaller than large screens it will create a full width, this will allow us to create a column effect when the screen is smaller.
You can now add padding to the div
that contains all of our blog post information:
<!--./src/components/BlogPage.vue-->
<article class="px-8 py-6 lg:w-1/3 md:w-full">
<div class="p-6 rounded-md">
...
Now for our cover image you are going to make the image rounded also and specific height so no matter what size image it will always look great!
<article class="px-8 py-6 lg:w-1/3 md:w-full">
<div class="p-6 rounded-md">
<img
class="object-cover object-center w-full h-40 mb-6 rounded"
src="http://via.placeholder.com/250x250"
alt="content"
/>
So you are creating a full width and height of h-40
(10rem) you are also using object-cover
which will make the image cover the container. Finally you are rounding the corners, your images should now look like:
For our blog title will will make the the text have a margin on the bottom and the text larger so it pops for our users:
<article class="px-8 py-6 lg:w-1/3 md:w-full">
<div class="p-6 rounded-md">
<img
class="object-cover object-center w-full h-40 mb-6 rounded"
src="http://via.placeholder.com/250x250"
alt="content"
/>
<h2 class="mb-3 text-lg lg:text-2xl">
A blog post about my dog
</h2>
As you can see for any screen it should have large text, and only on large screen it should be 2xl, now you just need to take care of our excerpt and link to read more.
To handle our paragraph that is an excerpt you are going to use leading-relaxed
which actually means you are going to a 1.25 rem
to our line height and you will add a margin at the bottom also.
<!--./src/components/BlogPage.vue-->
<article class="px-8 py-6 lg:w-1/3 md:w-full">
<div class="p-6 rounded-md">
<img
class="object-cover object-center w-full h-40 mb-6 rounded"
src="http://via.placeholder.com/250x250"
alt="content"
/>
<h2 class="mb-3 text-lg lg:text-2xl">
A blog post about my dog
</h2>
<p class="mb-4 leading-relaxed">
Super awesome doggo, with a great smile.
</p>
So the final piece to the puzzle is the link to "read more"
, you are going to add some hover color change and then add some margin on the bottom, you are also going to make it inline-flex
and center the items.
<article class="px-8 py-6 lg:w-1/3 md:w-full">
<div class="p-6 rounded-md">
<img
class="object-cover object-center w-full h-40 mb-6 rounded"
src="http://via.placeholder.com/250x250"
alt="content"
/>
<h2 class="mb-3 text-lg lg:text-2xl">
A blog post about my dog
</h2>
<p class="mb-4 leading-relaxed">
Super awesome doggo, with a great smile.
</p>
<a
href="#"
class="inline-flex items-center md:mb-2 lg:mb-0 hover:text-blue-400 "
>
Read More
</a>
</div>
</article>
You now have a complete article
, so you can find the final commit here.
If you launch your application you should now see the following:
and on mobile you will see this:
Conclusion
You have now come to the end of our tutorial and created a blog page example using Tailwind, if you have been coding along while reading you would have learnt the following:
- Learnt how to install TailwindCSS and PostCSS and setup our Vue application to use them.
- Create a responsive Navigation Bar that allows your end users to navigate regardless of the size of their screen.
- Create a fully responsive Blog page with styled images, headings and excerpts and the option to read more.
Now you have a good base layer, you can start adding your own post to your Vue application and explore using the ability to create your own themes.