Styling dynamic HTML content in Vue & React with TailwindCSS
Tags: tailwindcss, vue, react, css
Published: 2024-05-13 08:57:39

I recently worked a bit in the main product of [Alokai](https://alokai.com/) -> The Unified Storefront, and my work was primarly focused on improving performance of the project. I will share about my interesting findings in the next blog post :)

One of my findings was related to components that are usually paired with Content Management Systems (CMS) to display dynamic content on the website. In order to optimize these components, I needed to develop a new functionality in both Vue and React frameworks (as we support both in the product).

Implementing these improvements in Vue (Nuxt) was relatively easy because I work with it everyday, but doing so in React (Next) was a bit of a challenge.

And considering that during my development, I haven't found a simple solution to solve this problem (especially in React) and my solution was a mix of few answers, I decided to write this article to make it easier for you :)

Enjoy!

## 🤔 What is the use case here?

In general, the use case is to have a component that will be able to automatically style the content that will be received from CMS. The issue here is that we want to accept pure HTML as a content.

So, we want to be able to pass following HTML in CMS:

```html
<h1>Hello World</h1>
```

And by using our component like so:

```html
<Editorial content="htmlContentFromCMS" />
```

Automatically apply styling so that the final HTML would look like this:

```html
<h1 class="text-2xl">Hello World</h1>
```

Sounds interesting right? Let's take a look how we can achieve that in both Vue and React frameworks :)

## 🟢 Dynamic HTML styling in Vue

In Vue/Nuxt, this concept can be implemented relatively simple. 

In the template section we need a simple `div` tag where we will pass raw HTML that we will get from the CMS:

```vue
<template>
  <div v-html="content" />
</template>
```

In the script section, we only want to define props of our component to allow it to accept `content` prop that will contain the HTML content from CMS.

```vue
<script lang="ts" setup>
defineProps({
  content: {
    type: String,
    default: '',
  }
});
</script>
```

And in the style section, we want to create rules for the HTML tags and the styling that we will create in our design system:

```vue
<style scoped>
:deep(h1) {
  @apply text-2xl;
}
</style>
```

Notice that the style section has an attribute `scoped` which means that this styling will be only applied as a part of this component but as this HTML from CMS is different content that statically in the component, we need to pass a `:deep` helper before the tag name (`h1`). Thanks to this, we will style the content receive from CMS but other global tags h1 won't be affected.

## 🔵 Dynamic HTML styling in React

In React/Next, this is a bit more complex. First of all, in React components, we don't have that simple way of creating styles per tag/class/id without using an external library like styled components.

The solution to this would be to use the css modules that you can read more [here](https://nextjs.org/docs/messages/css-global). But this solution also comes with some problems because with it, we cannot style the tags properly receiving following error:

```
Selector "h1" is not pure (pure selectors must contain at least one local class or id)
```

You can read more about this issue [here](https://stackoverflow.com/questions/62851329/react-css-modules-applying-styles-to-native-html-tags) and [here](https://github.com/vercel/next.js/issues/55053)

Thanks to all these resources, I have found a solution that is working in my case.

First, let's create a `editorial.module.css` file:

```css
// editorial.module.css

.editorial h1 {
  @apply text-2xl;
}
```

Notice the `.editorial` class. This is a way of bypassing the issue with pure selectors. Otherwise the style would not be applied.

Next, in our component:

```tsx
import styles from './editorial.module.css';

type EditorialProps = {
  content?: string;
};

export default function Editorial({ content }: EditorialProps) {
  return (
    <div dangerouslySetInnerHTML={{ __html: content }} className={styles.editorial} />
  );
}
```

Let's stop for a second to explain each step here:

1. We import the styles from the module css file.
2. We define a type for the props that this component will accept
3. We create a new component and export it that accepts the content as a prop
4. This component will return inner HTML with the content from CMS and as a class name, we will pass the styles from module css file

And that's how it works!

## 📖 Learn more 

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this [link](https://vueschool.io/courses?friend=baroshem) or by clicking the image below:

[![Vue School Link](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i662jpyni4zs2dlaeud1.png)](https://vueschool.io/courses?friend=baroshem)

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉

## ✅ Summary

Well done! You have just learned how to create a component in Vue and React that will be able to display content in a form of a pure HTML fetched from CMS. 

Take care and see you next time!

And happy coding as always 🖥️