Search code examples
reactjstailwind-cssnext.js13

Read .html files from the next.js react public/assets and format it with tailwind.css


I'm learning next.js with React with tailwind css and was looking to read html static files from the public/assets folder:

import React from 'react';
import fs from 'node:fs';

import parse from 'node-html-parser';

const HTMLComponent = ({ filename }  : string) => {

  try {
    const htmlContent = fs.readFileSync(`./public/assets/html/${filename}`, 'utf-8');

    return (
      <div dangerouslySetInnerHTML={{ __html: htmlContent }} />
    );
  } catch (err) {
    console.error(`Error reading file: ${err}`);
  }
 
};

export default HTMLComponent;

I then use the component like this:

import HTMLComponent from '@/components/shared/HTMLFile';
export default function Page() {

  return (
    <div className='p-4'>

    <HTMLComponent filename = "index.html" />
    </div>
  );
}

Even though the index.html is formatted with h1, p and so on; none of that css formatting shows up in the displayed page.

I suspect that dangerouslySetInnerHTML is my nemesis.

Is there a better way to do this and get properly formatted css'd html?

The page has a header (which should import tailwind css) layout and footer. The included HTMLComponent is rendered on the page as all < p >s even though there are < h1 > tags present. The generated css has classes like:

@media (min-width: 768px) {

  .h1 {
    font-size: 36px;
    line-height: 44px;
  }
}

Your answers are much appreciated!


Solution

  • dangerouslySetInnerHTML only allows you to insert raw HTML into a component, it doesn't automatically apply styling from external CSS to the inserted HTML content.

    Try parsing the HTML content using node-html-parser to extract specific elements and apply Tailwind classes directly in your React component:

    import React from 'react';
    import parse from 'node-html-parser';
    
    const HTMLComponent = ({ filename }) => {
      const parsedHTML = parse(fs.readFileSync(`./public/assets/html/${filename}`, 'utf-8'));
      const h1Element = parsedHTML.querySelector('h1');
    
      return (
        <div>
          <h1 className="text-3xl font-bold">{h1Element.text}</h1>
          {/* Other elements with Tailwind classes */}
        </div>
      );
    };
    

    If the external HTML files contain their own CSS, import those css flies within your component using next/head:

    import Head from 'next/head';
    
    const HTMLComponent = ({ filename }) => {
      const htmlContent = fs.readFileSync(`./public/assets/html/${filename}`, 'utf-8');
      const parsedHTML = parse(htmlContent);
      const cssLinks = parsedHTML.querySelectorAll('link[rel="stylesheet"]');
    
      return (
        <div>
          <Head>
            {cssLinks.map((link) => (
              <link key={link.href} rel="stylesheet" href={link.href} />
            ))}
          </Head>
          <div dangerouslySetInnerHTML={{ __html: parsedHTML.body.innerHTML }} />
        </div>
      );
    };
    

    Also consider rendering the HTML files on the server using Next.js's SSR capabilities:

    // In a page component or API route
    export async function getStaticProps() {
      const htmlContent = fs.readFileSync(`./public/assets/html/index.html`, 'utf-8');
    
      return {
        props: {
          renderedHTML: htmlContent,
        },
      };
    }
    
    export default function Page({ renderedHTML }) {
      return (
        <div dangerouslySetInnerHTML={{ __html: renderedHTML }} />
      );
    }