Scalable vector word clouds

Canvas is great for static exports and huge word counts, but SVG shines when you need crisp text at any zoom level, per-word DOM nodes, or CSS-driven styling. The layout step is identical — only the renderer changes. Each placement becomes an SVG <text> element positioned with a transform.

When to pick SVG over Canvas. Dashboards that scale with CSS, print/PDF exports, accessibility (screen readers can traverse words), and light interactivity without manual hit-testing. For 5 000+ words or animation-heavy scenes, Canvas or WebGL is usually faster.

SVG rendering checklist:

  1. Set viewBox="0 0 width height" to match the layout bounds passed to layout().
  2. Use text-anchor="middle" and dominant-baseline="central" — the engine returns bbox centers, same as Canvas center anchoring.
  3. Apply rotation with transform="translate(x,y) rotate(deg)" on each <text> (or a wrapping <g>).
  4. Let width: 100% on the SVG scale the cloud responsively; re-run layout when the container's pixel size changes materially.

Step by step

Step 1

Build SVG from placements

render-svg.js
/** @param {SVGElement} svg — empty <svg> in the DOM */
export function drawWordCloudSvg(svg, placements, width, height, palette = ["#1f6feb"]) {
  svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
  svg.replaceChildren();

  for (let i = 0; i < placements.length; i++) {
    const p = placements[i];
    const el = document.createElementNS("http://www.w3.org/2000/svg", "text");
    el.textContent = p.text;
    el.setAttribute("font-size", String(p.fontSize));
    el.setAttribute("fill", palette[i % palette.length]);
    el.setAttribute("text-anchor", "middle");
    el.setAttribute("dominant-baseline", "central");
    el.setAttribute(
      "transform",
      p.rotation
        ? `translate(${p.x},${p.y}) rotate(${p.rotation})`
        : `translate(${p.x},${p.y})`,
    );
    svg.appendChild(el);
  }
}
Step 2

Style words with CSS

Because each word is a DOM node, you can target svg text globally or assign per-word classes. Hover transitions, selection highlights, and theme switches become ordinary CSS — no redraw loop required.

styles.css
.word-cloud-svg text {
  font-family: system-ui, sans-serif;
  cursor: default;
  transition: opacity 0.15s;
}
.word-cloud-svg text:hover {
  opacity: 0.75;
}

Try it yourself

Random datasets at 50 or 500 words, rendered as SVG. Resize the browser window — the cloud scales smoothly because viewBox maps layout coordinates to the container.

live svg

Press Esc or click Exit fullscreen to return to the demo card.

Presets tune minFontSize / maxFontSize so words stay readable at each scale (50 → 16–88px, 500 → 10–52px). Fullscreen lays out against the viewport so you can see the engine's maximum placement count.