DEV Community

Narcisa
Narcisa

Posted on

[Tailwind CSS] From CSS to Tailwind CSS

As part of the Micro Frontends series, we developed some micro applications based on Angular (dashboard micro application and heroes micro application). We started from the Angular Tour of Heroes tutorial and until now, we didn't care about anything related to styling.

Check-out the repository for the source code https://github.com/blminami/tour-of-heroes-microfrontends

Today, we're going to add Tailwind CSS to our NX workspace and style the dashboard application. Have a look at the screenshots below (before and after) to see what we want to achieve.

Before

Image description

After

Image description

Let's start by running the following command which will add tailwindcss config to the workspace:

npx nx generate @nrwl/angular:setup-tailwind dashboard-microapp
Enter fullscreen mode Exit fullscreen mode

According to the NX documentation, the command will install the dependencies and add the configuration files.

// tailwind.config.js

const { createGlobPatternsForDependencies } = require('@nrwl/angular/tailwind');
const { join } = require('path');

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'),
    ...createGlobPatternsForDependencies(__dirname),
  ],
  theme: {
    extend: {
      colors: {
        primary: '#E4B363',
        secondary: '#074F57',
        cordovan: '#c45663',
        'dark-bg': '#242424',
      },
    },
  },
  plugins: [],
};
Enter fullscreen mode Exit fullscreen mode

As part of tailwind.config.js file, we can extend the default theme by adding custom colors and other properties. For demo purposes, I updated the color palette to include some new colors.

/* dashboard.component.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Also, we have to import TailwindCSS bases style. In order to work in the micro frontend context, the styles have to be added at component level, instead of styles.css file.

Now that the configuration is done, we can switch to the html files and use the pre-defined classes to style the components.

First thing, let's have a look at the hero-search component, which exposes the functionality to search a hero by name.

<div class="flex flex-col items-center mb-4">
  <input
    #searchBox
    id="search-box"
    (input)="search(searchBox.value)"
    placeholder="Search for a hero"
    class="shadow appearance-none border rounded w-2/5 py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
  />
  <ul
    *ngIf="heroes$ | async as heroes; else null"
    class="shadow appearance-none border bg-white rounded w-2/5 py-2 px-3 text-gray-700 leading-tight mt-px cursor-pointer"
  >
    <li *ngFor="let hero of heroes" class="mt-1">
      <a routerLink="/heroes/detail/{{ hero.id }}">
        {{ hero.name }}
      </a>
    </li>
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

It consists of an input element and a list of heroes that meet the search criteria. We would like to have the 2 elements on separated rows and centered. To achieve it, we add a div container with the following classes class="flex flex-col items-center mb-4" which applies flex display, centers the items and add a margin bottom.
Let's also have a look at the input element and the classes class="shadow appearance-none border rounded w-2/5 py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
What we got: an element with shadow, rounded border (border-radius: 0.25rem; /* 4px */), width 40%, vertical and horizontal padding (py-2 px-3) and gray-700 text color.
For more details, check out the Tailwind documentation

Next, let's give life to our heroes! Instead of displaying boring hero cards, let's have an image, a name and a description of their super powers. We display the top heroes, after all, they deserve some recognition for their powers, right?πŸ˜„

In the in-memory-data.service.ts, update the heroes array and add the following properties to each object: id, name, description, image. Find the new array of data here.

{
        id: 13,
        name: 'Bombasto',
        description:
          'Telekinesis: The hero can move objects with their mind, allowing them to lift heavy objects or even people',
        image: 'https://i.postimg.cc/3wZMGqn8/11-2-anime-png-picture.png',
},
Enter fullscreen mode Exit fullscreen mode

For each hero, we're going to have a container that has rounded corners, box-shadow, cursor pointer and a gradient as background color (you can be creative with the gradients, here is a interesting list of options https://hypercolor.dev/)
class="rounded flex shadow-lg mb-2 mr-2 bg-gradient-to-br from-gray-200 via-gray-400 to-gray-600 cursor-pointer".
Also, we're going to display the name, image and description of the hero, in 2 different columns.

<div
      *ngFor="let hero of heroes"
      class="rounded flex shadow-lg mb-2 mr-2 bg-gradient-to-br from-gray-200 via-gray-400 to-gray-600 cursor-pointer"
      routerLink="/heroes/detail/{{ hero.id }}"
    >
      <img
        class="object-contain h-52 w-40 self-center"
        [src]="hero.image || defaultImage"
        alt="hero image"
      />
      <div class="px-6 py-4">
        <div class="font-bold text-xl mb-2">{{ hero.name }}</div>
        <p class="text-test text-base">
          {{ hero.description }}
        </p>
      </div>
    </div>
Enter fullscreen mode Exit fullscreen mode

Results:

Image description

Easy-peasy, right? πŸ₯³

✨Check out the Github repo for the entire configuration!

Until next time, thank you for reading! 🐾

Top comments (0)