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!
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 }} />
);
}