The main pieces are:
- serializing the component DOM tree as HTML using
Element.outerHTML
(orElement.innerHTML
if you’re sure that’s what you want) on aref
- creating a
File
from the HTML - initiating the download of the
File
Here’s an example of how you could do it (adjust to your needs):
Note that, unfortunately, Stack Overflow doesn’t set
allow-downloads
on thesandbox
attribute of the iframe used to render the live snippet demo (so the actual download won’t happen when you click a button). Copy + paste this example into an HTML file and run in a local dev server to see it working.
<div id="root"></div><script src="https://unpkg.com/[email protected]/umd/react.development.js"></script><script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script><script>Babel.registerPreset('tsx', {presets: [[Babel.availablePresets['typescript'], {allExtensions: true, isTSX: true}]]});</script>
<script type="text/babel" data-type="module" data-presets="tsx,react">
const {useRef} = React;
function createHTMLFile (fileName: string, html: string): File {
return new File([html], fileName, {type: 'text/html'});
}
function saveFile (file: File): void {
const oUrl = URL.createObjectURL(file);
const a = document.createElement('a');
a.style.setProperty('display', 'none');
a.href = oUrl;
a.download = file.name;
document.body.appendChild(a);
a.click();
a.remove();
// 10s is arbitrary, but is more than enough for the user to download the HTML
// even if they're preseneted with a download confirmation prompt by their
// browser:
const delay = 10_000;
// the important part is that you clean up the object URL so that you don't
// leak memory for every click (since they aren't garbage collected)
setTimeout(() => URL.revokeObjectURL(oUrl), delay);
};
function Downloadable (props: { children?: React.ReactNode; }): React.ReactElement {
const ref = useRef<HTMLDivElement>(null);
const handleClick = () => {
const div = ref.current;
if (!div) return;
const html = div.outerHTML;
const fileName = `component.html`;
saveFile(createHTMLFile(fileName, html));
};
return (
<div>
<button onClick={handleClick}>Download as HTML</button>
<div {...{ref}}>{props.children}</div>
</div>
);
}
function Example (): React.ReactElement {
return (
<>
<Downloadable>
<header>
<h1>hello world</h1>
<p>description</p>
</header>
</Downloadable>
<Downloadable>
<h2>a list</h2>
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</Downloadable>
</>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
</script>
CLICK HERE to find out more related problems solutions.