DEV Community

Cover image for Nuxt Tutorial 7 - UI Integrations
Alois Sečkár
Alois Sečkár Subscriber

Posted on

Nuxt Tutorial 7 - UI Integrations

In the previous part we dealt with CSS; now we’ll move on to more advanced UI integrations. Just like with styling, you don’t necessarily need to reinvent the wheel. Instead of building every functional element from scratch, it’s usually easier to reach for a dedicated library.

We’ll go through four practical integration examples. The selection isn’t driven by any deep logic - these are simply technologies I’ve come across and needed them in my Nuxt projects. Still, they demonstrate some general techniques you can reuse if you ever need to integrate something similar. At the end of the article, you’ll also find links to ready-made integrations for other well-known UI libraries from the Vue ecosystem. Let’s dive in.

Bootstrap

Bootstrap used to be - and may still be - the most popular CSS framework for fast, responsive web development. It includes a set of predefined CSS classes, components, and JS plugins that make it easier to build modern design, responsive layouts, forms, navigation, and other interactive elements. It goes further than the previously covered Tailwind CSS, which focuses solely on styling.

Personally, I never really like it. If you’re starting today, I’d rather recommend combining Tailwind CSS with some library specialized in form controls (one of the next articles will cover those). But many developers are used to Bootstrap from earlier days, and of course Nuxt doesn’t prevent you from continuing to use it.

Nuxt integration

You can find some Bootstrap solutions in the Nuxt modules directory, but I had doubts about how up-to-date they are, so I chose a DIY approach via a Nuxt plugin. We haven’t covered plugins yet, but they’re an effective way to add new functionality to a base Nuxt app.

A quick explanatory aside: Nuxt plugin in this context is a file in the /app/plugins folder that can enrich the Nuxt instance - or even the underlying Vue.js app - via a dedicated function. Nuxt loads these files automatically and runs them at startup.

In your project you need dependencies on the NPM package bootstrap and on sass (similar to Open Props, you’ll need some extra CSS processing for your input stylesheet and this is the recommended way). Import Bootstrap styles in the main .scss file in /app/assets/:

/* /app/assets/main.scss */
@import 'bootstrap/scss/bootstrap';
Enter fullscreen mode Exit fullscreen mode

In nuxt.config.ts we must register this file via css option:

// /nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/main.scss']
  // ...
})
Enter fullscreen mode Exit fullscreen mode

Finally, we also need a plugin that provides interactivity to the Nuxt app via Bootstrap JS. These three lines will do:

// /app/plugins/Bootstrap.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.provide('bootstrap', import('bootstrap'))
})
Enter fullscreen mode Exit fullscreen mode

The defineNuxtPlugin function is the handler mentioned above. Its callback receives the Nuxt app instance and lets you interact with it in various ways via its exposed API. For example, using provide you can provide everything that the bootstrap package offers through its exports.

You can find the source code of a simple example implementation here:
nuxt-bootstrap @ GitHub and see it in action.

DevExtreme

The DevExtreme UI library was first introduced to me by an “Angular guy” colleague. It’s framework agnostic though, so you can use it in Vue as well. The main downside is obvious right away: it’s paid — and not cheap. On the other hand, we used it on a larger real-world project at work, and I have to say building complex nested forms (assembled entirely from scratch) was incredibly smooth with DevExtreme. Their layouts also made it reasonably responsive. The documentation is high quality too, although it took me a bit to learn how to navigate through it.

Another small blemish is that for some reason Dx components don’t work with Server-Side Rendering - or at least, even after several years I never figured out what needed to be done. So you need to set ssr: false and accept that the app will render via JavaScript only in the client’s browser. That makes it more suitable for SPAs (Single Page Applications), where users treat the website more like a desktop application and are willing to wait a bit for the content to load - which was our case. For projects where loading speed and SEO are critical (typically e-shops), it might not be the best fit.

Nuxt integration

In package.json you need to reference the base NPM package devextreme and its Vue port devextreme-vue. That alone is enough for local development, but the problem is that “tree-shaking” (removing unused dependencies from the production build) doesn’t recognize you’re using its components, and it happily strips all the definitions out of the final bundle.

I struggled with this for quite a while and eventually had to get help. The key is, again, a Nuxt plugin where you gradually register the DevExtreme components you want to use as Vue components. I strongly recommend registering them under the same names DevExtreme uses — otherwise you lose the ability to easily search their documentation.

In this example I only use a basic button, but the principle is the same for everything else:

// /app/plugins/DevExtreme.ts
import { DxButton } from 'devextreme-vue/button'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component('DxButton', DxButton)
})
Enter fullscreen mode Exit fullscreen mode

The DxButton component then becomes globally available in all your app’s component templates, and you can use it anywhere exactly as described in the DevExtreme documentation without additional constraints.

You can find the source code of the example implementation here:
nuxt-dx @ GitHub

After starting the app, you’ll notice a very prominent license warning in the header that DevExtreme injects into the unregistered version. That’s a reminder that without a purchased license, this integration won’t help you much. Still, we’ve demonstrated the general principle of using plugins to add any external Vue components into Nuxt.

FontAwesome

After general-purpose UI libraries, let’s move to FontAwesome, a popular solution for displaying icons on websites and in apps. It provides a wide selection of vector icons in SVG form (and also as font files) that you can easily use via CSS. FontAwesome allows simple manipulation of icons: changing size, color, and more.

“FA” used to be an evergreen in web design a few years ago, similar to Bootstrap. I think it’s past its peak too, but let’s still take a look. Since the time I solved the integration manually, a module has been created, so it may be easier today than what I describe below. My solution requires at least three new dependencies in package.json (more if you want to use icons from additional (paid!) sets), and overall it feels a bit clunky to me. But if you’re used to it and can list FontAwesome icon names off the top of your head, you can bring it into Nuxt with you.

The downside is that, like DevExtreme, FontAwesome doesn’t play nicely with Nuxt SSR, so you need to set ssr: false.

Nuxt integration

I integrated FA into a Nuxt project using a plugin again. This time it’s a bit less intuitive: you first extend the library object with the icon definitions you want to use, then take the FontAwesomeIcon object (from another FA package) and register it as a Vue component inside your app:

// /app/plugins/FontAwesome.ts
import {
  faEnvelope, faFaceSmile, faHouse
} from '@fortawesome/free-solid-svg-icons'
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

// these icons will be available as values for the "icon" attribute
library.add(faEnvelope)
library.add(faFaceSmile)
library.add(faHouse)

// register the "fa" component
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component('fa', FontAwesomeIcon)
})
Enter fullscreen mode Exit fullscreen mode

In component templates you can then use the <fa> component like this:

<fa class="icon" icon="envelope" title="FA 'envelope' icon" />
Enter fullscreen mode Exit fullscreen mode

You can find the source code of the example implementation here:
nuxt-fa @ GitHub

Icônes

Because I don’t consider the solution above particularly good, I’d like to immediately present an alternative. Icônes is a project focused on providing a large collection of icons for websites and apps. It offers a wide selection of SVG vector icons that are easy to use and customize. Icônes makes icon integration simpler and helps improve the visual quality of user interfaces.

If you ask me what to use for icons, I’ll recommend Icônes without hesitation. It gives you an easy way to get SVG-based definitions that are portable across environments, requires no new dependencies, and offers a huge library of icon definitions for free. In Nuxt - or rather, directly in Vue - you can introduce each icon as its own component. If you’re not using a UI library that handles icons in its own way (see e.g. the upcoming article about Nuxt UI), this is an excellent lightweight option that lets you use only what you actually need.

Nuxt integration

Unlike previous, this truly works without any external dependency. You simply find the icon you want on the Icônes website and export the source code directly as a Vue component. In my demo, three selected icons are copied this way into the /components folder.

You can find the source code of the example implementation here:
nuxt-icones @ GitHub

Universal icon component

You may have noticed (as I did) that these generated components look almost identical and differ only in their <svg> and <path> definitions.

In another project, I therefore have a component that renders one of predefined Icônes icons based on a definition from a data file. When the app needs a new icon, a new definition is added into the JSON file and linked from icon component. Feel free to use this idea as inspiration in your own projects.

Wrap up

In this article, we saw four examples of integrating external UI libraries into a Nuxt app. It’s definitely not an exhaustive list of your options, but I think it’s a solid starting point for inspiration.

In many cases, there’s already a ready-made Nuxt module for popular technologies that handles the integration for you. For example:

I don’t have personal experience with any of these, but you’ll surely find support in the active and friendly Nuxt community. And if you have a favorite CSS framework or UI library and you’re missing a Nuxt setup guide, reach me through a comment below and we can try to figure out the integration.

Next time, we’ll take a closer look at one more option that I intentionally left out so far - and also quickly adopted as my own: the Nuxt UI module directly from the Nuxt team.

Top comments (0)