<Html>
component for react-pdf
- Support for CSS via
<style>
tags andstyle
attributes (limited toStyle
properties supported byreact-pdf
) - Browser CSS defaults with option for style reset
- Basic
<table>
(attempted using flex layouts)<ul>
and<ol>
support - Ability to provide custom renderers for any tag
- Support for inline
<style>
tags and remote stylesheets (using fetch)
- Parses the HTML string into a JSON tree of nodes using node-html-parser
- Parses any
<style>
tags in the document andstyle
attributes using css-tree - Renders all nodes using the appropriate
react-pdf
components, applying cascading styles for each node as an array passed to thestyle
prop:- block/container nodes using
<View>
- inline/text nodes using
<Text>
, with appropriate nesting and collapsing of whitepace <img>
nodes using<Image>
<a>
nodes using<Link>
- block/container nodes using
npm i react-pdf-html
OR
yarn add react-pdf-html
import Html from 'react-pdf-html';
const html = `<html>
<body>
<style>
.my-heading4 {
background: darkgreen;
color: white;
}
pre {
background-color: #eee;
padding: 10px;
}
</style>
<h1>Heading 1</h1>
<h2 style="background-color: pink">Heading 2</h2>
<h3>Heading 3</h3>
<h4 class="my-heading4">Heading 4</h4>
<p>
Paragraph with <strong>bold</strong>, <i>italic</i>, <u>underline</u>,
<s>strikethrough</s>,
<strong><u><s><i>and all of the above</i></s></u></strong>
</p>
<p>
Paragraph with image <img src="${myFile}" /> and
<a href="http://google.com">link</a>
</p>
<hr />
<ul>
<li>Unordered item</li>
<li>Unordered item</li>
</ul>
<ol>
<li>Ordered item</li>
<li>Ordered item</li>
</ol>
<br /><br /><br /><br /><br />
Text outside of any tags
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Foo</td>
<td>Bar</td>
<td>Foobar</td>
</tr>
<tr>
<td colspan="2">Foo</td>
<td>Bar</td>
</tr>
<tr>
<td>Some longer thing</td>
<td>Even more content than before!</td>
<td>Even more content than before!</td>
</tr>
</tbody>
</table>
<div style="width: 200px; height: 200px; background: pink"></div>
<pre>
function myCode() {
const foo = 'bar';
}
</pre>
</body>
</html>
`;
return (
<Document>
<Page>
<Html>{html}</Html>
</Page>
</Document>
);
import ReactDOMServer from 'react-dom/server';
const element = (
<html>
<body>
<style>
{`
.heading4 {
background: darkgreen;
color: white;
}
pre {
background-color: #eee;
padding: 10px;
}`}
</style>
<h1>Heading 1</h1>
<h2 style={{ backgroundColor: 'pink' }}>Heading 2</h2>
...
</body>
</html>
);
const html = ReactDOMServer.renderToStaticMarkup(element);
return (
<Document>
<Page>
<Html>{html}</Html>
</Page>
</Document>
);
type HtmlProps = {
children: string; // the HTML
collapse?: boolean; // Default: true. Collapse whitespace. If false, render newlines as breaks
renderers?: HtmlRenderers; // Mapping of { tagName: HtmlRenderer }
style?: Style | Style[]; // Html root View style
stylesheet?: HtmlStyles | HtmlStyles[]; // Mapping of { selector: Style }
resetStyles?: false; // If true, style/CSS reset
};
const stylesheet = {
// clear margins for all <p> tags
p: {
margin: 0,
},
// add pink background color to elements with class="special"
['.special']: {
backgroundColor: 'pink',
},
};
return (
<Document>
<Page>
<Html stylesheet={stylesheet}>{html}</Html>
</Page>
</Document>
);
const html = `<div style="width: 200px; height: 200px; background-color: pink">Foobar</div>`;
return (
<Document>
<Page>
<Html>{html}</Html>
</Page>
</Document>
);
Remote styles must be resolve asynchronously, outside of the React rendering, because react-pdf doesn't support asynchronous rendering
import { fetchStylesheets } from 'react-pdf-html';
const html = `<html>
<head>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
crossorigin="anonymous" />
</head>
<body>
<div></div>
</body>
</html>`;
const stylesheets = await fetchStylesheets(html, {
...fetchOptions
});
...
return (
<Document>
<Page>
<Html stylesheet={stylesheets}>{html}</Html>
</Page>
</Document>
);
Reset browser default styles (see CSS reset)
return (
<Document>
<Page>
<Html resetStyles>{html}</Html>
</Page>
</Document>
);
The default styesheet roughly matches browser defaults, using a rough emulation of ems:
const em = (em: number, relativeSize: number = fontSize) => em * relativeSize;
StyleSheet.create({
h1: {
fontSize: em(2),
marginVertical: em(0.67, em(2)),
fontWeight: 'bold',
},
...
});
By default, the basis for the font size ems is based on the fontSize
from props.style
:
return (
<Document>
<Page>
<Html style={{ fontSize: 10 }}>{html}</Html>
</Page>
</Document>
);
If this is not defined, it falls back to a default of 18
Please note that react-pdf
has some constraints with how fonts are applied (see https://react-pdf.org/fonts). You must provide a different font file for each combination of bold, italic, etc. For example:
Font.register({
family: 'OpenSans',
fonts: [
{ src: fonts + '/Open_Sans/OpenSans-Regular.ttf' },
{ src: fonts + '/Open_Sans/OpenSans-Bold.ttf', fontWeight: 'bold' },
{ src: fonts + '/Open_Sans/OpenSans-Italic.ttf', fontStyle: 'italic' },
{
src: fonts + '/Open_Sans/OpenSans-BoldItalic.ttf',
fontWeight: 'bold',
fontStyle: 'italic',
},
],
});