Skip to content
Wait for Rendering

Wait for Rendering

The server captures the page as soon as the DOM has loaded. Anything a script draws after that point, which covers most charting libraries, is not there yet, and the PDF comes back with an empty space where the chart should be. Nothing errors.

Tell it what to wait for:

doc.WaitVisible(".highcharts-root", selector.ByQueryAll)

Now the capture blocks until an element matching that selector is present and visible. A chart library that appends an <svg> when it finishes gives you a reliable thing to wait on.

Three ways to wait

CallWaits forUse when
WaitReady(sel, by)The element exists in the DOMThe element is added late but may be hidden
WaitVisible(sel, by)The element exists and is visibleThe usual choice for charts and images
WaitTime(d)A fixed duration, unconditionallyThere is nothing specific to wait for

Prefer a selector. WaitTime pays its full cost on every conversion whether the page was ready in 50ms or not, and it still guesses wrong when the network is slow. Reach for it when the completion signal is not visible in the DOM, for instance a canvas that is drawn into rather than replaced.

Both selector calls can be used more than once, and every selector registered has to be satisfied before the capture happens.

Matching modes

The second argument decides how the selector is interpreted. It defaults to selector.BySearch when omitted.

ModeEquivalent to
selector.BySearchDOM.performSearch, accepts both CSS and XPath
selector.ByQuerydocument.querySelector()
selector.ByQueryAlldocument.querySelectorAll()
selector.ByIDdocument.querySelector('#' + id)
selector.ByNodeIDA numeric DevTools node id
selector.ByJSPathA Chrome DevTools “JS Path” expression

ByQueryAll is the right one for a page with several charts, since it waits on all matches rather than the first. ByJSPath passes the selector to Runtime.evaluate, so keep untrusted input out of it.

Limitations

A selector that never appears does not fail fast. The conversion runs until the timeout expires and then returns that error, so a typo in a class name costs you the full 15 seconds. Check the selector in a browser first.

WaitTime is capped at three minutes and is rejected client-side above that, with too long minimum load time. Maximum is 3 minutes. The server caps a whole query at ten minutes.

Waiting does not buy you more time. The conversion wraps its request in a 15 second context regardless of what you are waiting for, so a wait plus a slow render that add up to more than that fails even though each part was reasonable. Raise the ceiling explicitly:

doc.SetTimeoutDuration(60 * time.Second)

Scripts loaded from a CDN need the container to reach the internet. Without outbound access the library never loads, the selector never appears, and the failure looks like a timeout rather than a network problem.

Run the example

graph.go converts graph.html, a Highcharts dashboard that pulls its library from code.highcharts.com and draws several charts and a world map into the DOM. It waits on .highcharts-root with ByQueryAll, then writes the PDF with htmlDocument.WriteToFile, which is the one example here that never touches a creator.Creator.

Drop the WaitVisible line and run it again: the layout and headings come through and every chart is blank. That is the failure this page exists to prevent.

git clone https://github.com/unidoc/unihtml-examples.git
cd unihtml-examples/graph
go run graph.go localhost:8080

If this is your first time using UniHTML, follow the getting started guide to create an API key and set up your development environment.

View the full source

Sample input

The Highcharts dashboard in a browser

Sample output

The same dashboard converted to PDF with the charts drawn

Last updated on