Nuxt Tutorial 7 - Adopting CSS

Published: (December 21, 2025 at 12:46 PM EST)
6 min read
Source: Dev.to

Source: Dev.to

Import CSS

If you’re migrating an older project, you might already have your .css style files ready. Or you may be using a service that ships its styles as a standalone .css file (e.g., when using Bootstrap from a CDN). Nuxt offers a very simple integration for these cases.

  1. Upload your style files into the /app/assets folder (usually into a /css sub‑directory for better clarity).
  2. Reference them via the css option in your nuxt.config.ts file:
export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
  // …
})

The imported styles are then automatically available across the whole application.

If needed, you can also load them individually per component:

In a script (e.g., <script setup>):

import '~/assets/css/main.css'

Or inside a <style> block:

@import url("~/assets/css/main.css");

Even with just this, you can achieve quite a lot. For examples of integrations with more advanced CSS libraries, keep reading.

Tailwind CSS

Tailwind CSS is a utility‑first CSS framework. Instead of writing custom classes, you compose the final look from a large set of predefined utility classes, which enables fast and flexible styling and layouts. Tailwind is also highly adaptable and configurable—e.g., you can define custom color schemes.

It deserves its own article (which I originally planned, and maybe I’ll get to it eventually). For me it’s currently the number‑one choice for building a website’s look. It requires a slightly different philosophy, but I adjusted in a day and haven’t looked back. I’ve migrated several personal projects to Tailwind, converting hand‑crafted designs into Tailwind utilities in a single evening.

It’s fair to note that Tailwind isn’t a “purist” framework; it imposes some constraints. Some critics argue that it creates too much abstraction and gives users the illusion that they understand what they’re doing—until they hit a trap they can’t resolve because they don’t know the underlying CSS. In my experience, it works well for the vast majority of situations, and its efficiency frees up time to handle edge cases.

Nuxt integration

Getting started with Tailwind CSS in Nuxt is straightforward. The creators ship a Vite plugin (the build tool Nuxt uses), which you install together with the main library:

npm install tailwindcss @tailwindcss/vite

Then add the plugin to nuxt.config.ts and reference a CSS file that imports Tailwind:

import tailwindcss from '@tailwindcss/vite'

export default defineNuxtConfig({
  // Vite integration plugin
  vite: {
    plugins: [tailwindcss()],
  },

  // CSS file importing Tailwind classes
  css: ['~/assets/css/tailwind.css'],

  // other config…
})

Create a simple CSS file (e.g., ~/assets/css/tailwind.css) that loads Tailwind:

@import "tailwindcss";

That’s all you need to start using Tailwind utilities in your Nuxt components.

Demo app

You can try the approach above in practice. The source code for the demo implementation is here:
nuxt‑tailwind @ GitHub

The demo focuses on both integration and usage. All visual behavior lives in /app/app.vue, which contains several examples of how Tailwind CSS can be applied. It also shows that utility classes can be freely combined with classic “plain” CSS.

In /app/assets/css/tailwind.css you can see how easily you can extend Tailwind’s default theme with your own colors or fonts if the base palette isn’t enough.

Based on a personal bad experience, I added a cautionary example to the demo alongside the positive ones. I’m risking that it might inspire someone to repeat the same mistake, but hopefully it will save many of you from unnecessary problems.

What is it about?
Tailwind’s authors encourage you to use utility classes directly in HTML templates as attributes on individual elements whenever possible. Not everyone (hi, former me) likes that, because:

  • Class lists can get really long
  • The same definitions repeat

At the same time, a beginner—armed with general programming truths and ready to “fix” things—will sooner or later discover the @apply directive, which seems to allow defining reusable classes in CSS files. And to be fair: it does allow it, and it works perfectly. The problem is that it severely obfuscates the intent of Tailwind’s utility‑first philosophy, leading to harder‑to‑maintain code and potential pitfalls. (The rest of the discussion continues in the demo repository.)

Implementation

After a few months you might forget that you styled a globally and wonder why your inline definitions don’t apply. The demo app includes a clear example with the colour of an HTML link at the bottom of the page. I wrote more about this in this article.

End of the diversion. Definitely take a look at Tailwind CSS – you might end up liking it like I do, along with thousands of other developers who prioritize speed and efficiency over perfect control via native CSS.

P.S.: Previously I handled the integration via a dedicated Nuxt module, which was a bit easier to set up (install + add the module). I’m not sure about its current status, though. After Tailwind v4 was released, it stopped working for me. Its new version has been stuck in beta for months, and it almost looks like its historical role is over. If the situation changes, I’ll come back and update this article.

Open Props

Open Props is based on a similar idea to Tailwind CSS – it provides a set of pre‑built styles that may constrain you a bit, but in return you don’t have to reinvent the wheel everywhere. Instead of shipping complete pre‑built CSS classes, Open Props encodes the styling information as CSS variables, which you can use and compose inside your own classes.

To be honest, Tailwind v4 also uses CSS variables, and you may have already tasted them (even unknowingly) – see how the demo app extends the default @theme.

Open Props sits one level lower. It doesn’t abstract away writing CSS entirely; it only provides ready‑made, proven values. That gives you more freedom, but it’s a bit more work. The main advantage is how lightweight and scalable it is – the library lets you use only the small subset you actually need.

Nuxt integration

Because Nuxt (Vue) can’t replace CSS variables with actual values at build time by itself, you need to add a CSS processor (postcss in my demo) along with a plugin that performs the substitution after being fed the definitions from Open Props. That’s about the only catch; otherwise you just import the open-props NPM package and start building CSS definitions. There is a showcase of a few styles in the demo.

What I like most about Open Props are the ready‑made gradients – smooth transitions between colours. Sure, it’s not that hard to write them yourself in plain CSS (I even watched a demo of building a “gradient editor” recently), but if you’re not a web designer at heart, who wants to grind through that?

The source code for the demo implementation is here:
nuxt-openprops @ GitHub

Summary

We’ve shown how to load internal and external CSS files into a Nuxt app, plus two examples of CSS libraries and how to integrate them. There are, of course, many other options. If you have a favourite UI/styling library, check whether it already has a Nuxt integration (most commonly in the form of a module). If not, it may be enough just to load the resulting CSS files the way we described at the start and use them directly.

If you get stuck, reach out and we can try to figure something out together.

In the upcoming tutorial article we’ll move from general styling to more advanced UI libraries, which provide not only styles but also pre‑built UI components. We’ll look at a few of them along with examples of integrating them into Nuxt.

Back to Blog

Related posts

Read more »

You Are Using TailwindCSS Wrong

I’ve mentioned before why I generally do not recommend using Tailwind CSS as the primary styling approach in my projects, and I have explained that position in...