Styling dynamic HTML content in Vue & React with TailwindCSS

jacobandrewsky

Jakub Andrzejewski

Posted on May 13, 2024

Styling dynamic HTML content in Vue & React with TailwindCSS

I recently worked a bit in the main product of Alokai -> 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:



<h1>Hello World</h1>


Enter fullscreen mode Exit fullscreen mode

And by using our component like so:



<Editorial content="htmlContentFromCMS" />


Enter fullscreen mode Exit fullscreen mode

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



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


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

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.



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


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

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. 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)


Enter fullscreen mode Exit fullscreen mode

You can read more about this issue here and here

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:



// editorial.module.css

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


Enter fullscreen mode Exit fullscreen mode

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:



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

type EditorialProps = {
  content?: string;
};

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


Enter fullscreen mode Exit fullscreen mode

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 or by clicking the image below:

Vue School Link

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 🖥️

💖 💪 🙅 🚩
jacobandrewsky
Jakub Andrzejewski

Posted on May 13, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related