SnapDOMGitHub8K
Framework Guide · Svelte 5

Capture a Svelte component

Bind the export surface to a DOM variable, then use tick() when the click also changes what Svelte renders.

TL;DR

bind:this gives you the element after mount. A plain download click can capture it immediately; if the click changes component state first, await tick() before calling SnapDOM.

Capture the state produced by the click

This Svelte 5 component reveals extra report detail and exports the resulting DOM. The button stays outside the bound article, so it never appears in the PNG.

npm install @zumer/snapdom
<script lang="ts">
  import { tick } from 'svelte'
  import { snapdom } from '@zumer/snapdom'

  let card: HTMLElement
  let expanded = $state(false)

  async function download() {
    expanded = true
    await tick()

    await snapdom.download(card, {
      format: 'png',
      filename: 'svelte-card.png',
      scale: 2,
    })
  }
</script>

<article bind:this={card}>
  <h2>Quarterly report</h2>
  {#if expanded}
    <p>Details added before capture.</p>
  {/if}
</article>

<button type="button" onclick={download}>Download PNG</button>

Without await tick(), the assignment has happened in JavaScript but the new paragraph may not exist in the DOM yet. If the handler does not change any state used by the card, there is no reason to add an extra tick.

When the bound element is conditional

bind:this is undefined until mount and becomes undefined again when an {#if} branch removes the element. Type the reference as optional and guard it when the export surface itself is conditional.

let card: HTMLElement | undefined

async function download() {
  await tick()
  if (!card) return
  await snapdom.download(card, { filename: 'card.png' })
}

Read the reference in an event handler, $effect, or onMount, never during component initialization.

What tick() does not wait for

tick() applies pending Svelte state changes. It does not finish a fetch, decode an image, load a web font, or run a transition to its final frame. Await the data promise first; await image.decode() or document.fonts.ready when either changes layout.

A capture taken during a Svelte transition: directive records the computed style at that moment. Wait for the intro or CSS transition to finish, or render a transition-free export surface when the final geometry matters.

SvelteKit and server rendering

SvelteKit may render the article on the server, but there is no browser layout to capture there. Keep SnapDOM calls in a click handler or onMount; onMount does not run during SSR. For an automatic export after navigation, await the route’s data, then tick(), then capture the bound element.

Frequently asked questions

Why is a bind:this reference undefined?

Svelte assigns bind:this after the element mounts. Read it from an event handler, effect, or onMount, and guard it when the target is inside a conditional block.

What does tick() wait for?

tick() waits until pending Svelte state changes are applied to the DOM. It does not wait for fetches, image decoding, web fonts, or transitions.

Can SnapDOM run in SvelteKit SSR?

The capture itself must run in the browser because it needs layout and computed styles. Call it from a client event handler or onMount.

Export the bound Svelte element

Call SnapDOM from the click handler, and add tick() only when that action changes the rendered state first.

Open the demoInstall from npm