The surprisingly complex journey to text-selectable client-side generated PDFs
6 points by jeremiahlee
6 points by jeremiahlee
The author would likely be interested in Typst's PDF export, which generates selectable PDFs without issue, and can generate accessible PDFs for the PDF/UA-1 standard. And Typst's web-app runs on the client by downloading the compiler as WASM, although it may be easier to use a package like typst-ts instead.
Of course, Typst isn't compatible with Markdown, but is accepted by Pandoc for conversion. Or if they want, it wouldn't be too hard to convert most basic Markdown elements into Typst elements or syntax.
Huh, just yesterday I was staring at a superficially similar shaped problem but with somewhat different requirements and thus different solutions: in my case an element containing an arbitrary DOM tree (including SVG as well) styled with arbitrary CSS must be printable without blocking the browser.
We already have a solution for this which starts off fairly similar: walk the DOM tree and use getComputedStyle to get the necessary styles to reproduce the view. These are then used to create a new HTML document with unique classes created for each combination of styles and used instead of inline styling in the HTML text. Finally, this HTML text is then wrapped inside an SVG <foreignObject> element and the SVG is turned into a dataurl, which is then used as an iframe src, the iframe appended into DOM and its onload handler set to call frame.contentWindow.print(). This gets pixel-perfect rendering without blocking the browser's rendering thread which happens to be very important for us.
There are two big downsides though:
I implemented a nice little WebComponent only to notice that it doesn't appear in print! And of course it doesn't - the iframe doesn't have that WebComponent registered so it only renders its direct light-DOM contents which in this case happened to be nothing. So I had to do some copying of shadow-DOM elements and styles before printing to get things working again and ain't that just a pain. And it only worked because I controlled the WebComponent, but if some 3rd party component shows up then I'll be out of luck.
In the end I believe for our case the right solution to be just Ctrl+P and marvelous amounts of @media print {} CSS rules to hide the rest of the DOM not part of the element being printed. Since we're just printing the web page in front of us we'll get all WebComponents printing no problem and we'll get text selecting working as well, and best of all we won't be blocking the browser thread either as Ctrl+P is "asynchronous" unlike window.print().
The annoying part is getting the print styles working just right, and the hard part will be accepting that instead of using a print button to choose which element to print users will instead have to hover the element they want to print and just press Ctrl+P.