SVG cheat sheet
A scannable SVG reference: 12 short snippets across 8 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Shapes and coordinates | The viewBox establishes a user coordinate system of min-x min-y width height. Everything inside is drawn in those | lesson |
| Authoring, tooling and optimising SVG files | The practical default for most projects: inline the handful of icons whose colour or size changes with context, put | lesson |
| Paths in depth: commands, curves and arcs | One more habit worth adopting: keep the d attribute readable by putting one command per line with its parameters, and | lesson |
| Text, fonts and text on a path | Lay out text with tspan, control baselines, put text on a curve with textPath, and handle font loading honestly | lesson |
| Filters and visual effects | The honest summary: filters are the most expensive feature in the SVG toolbox and the most commonly overused. Every one | lesson |
| Responsive, fluid and data-driven SVG | One accessibility habit that applies to every hand-built chart: give the SVG role="img" and an aria-label summarising | lesson |
| Symbol sprites, icon systems and reuse | The last thing worth deciding early: whether your icons are decorative or meaningful. Decorative icons get | lesson |
| Performance, rendering cost and canvas trade-offs | The summary worth remembering: SVG wins on interactivity, accessibility, CSS styling, vector export and inspectability | lesson |
Quick snippets
Shapes and coordinates
The coordinate system
<svg viewBox="0 0 200 100" width="400" height="200" role="img" aria-label="A rectangle">
<rect x="10" y="10" width="180" height="80" />
</svg>
The coordinate system
<!-- fluid: no fixed height, the viewBox supplies the ratio -->
<svg viewBox="0 0 600 300" style="width: 100%; height: auto;">
<circle cx="300" cy="150" r="120" fill="none" stroke="#0ea5e9" stroke-width="4" />
</svg>
The drawing primitives
<svg viewBox="0 0 300 120" style="width: 100%; height: auto;">
<rect x="10" y="10" width="80" height="60" rx="8" fill="#e0e7ff" stroke="#4f46e5" />
<circle cx="140" cy="40" r="30" fill="#bae6fd" />
<ellipse cx="230" cy="40" rx="40" ry="24" fill="#fde68a" />
<polygon points="10,110 60,80 100,110" fill="#fca5a5" />
<polyline points="120,110 150,85 180,105 215,80" fill="none"
stroke="#0f766e" stroke-width="3" stroke-linejoin="round" />
</svg>Full lesson: Shapes and coordinates →
Authoring, tooling and optimising SVG files
SVGO with a deliberate configuration
npm install --save-dev svgo
# Inspect before you commit to a config
npx svgo --show-plugins
npx svgo --config svgo.config.mjs icon.svg -o icon.min.svg
# Batch a folder
npx svgo -f src/icons -o dist/icons --recursiveFull lesson: Authoring, tooling and optimising SVG files →
Paths in depth: commands, curves and arcs
Choosing a curve
<!-- A circle drawn with two arcs, and the same shape as four cubics.
Arcs are shorter and exactly circular; cubics are only approximately so. -->
<path d="M100 50 A 50 50 0 1 0 100 150 A 50 50 0 1 0 100 50" />
<!-- Rounded rectangle with arcs: rx and ry are the corner radii -->
<path d="M20 0 H80 A10 10 0 0 1 90 10 V50 A10 10 0 0 1 80 60 H20 A10 10 0 0 1 10 50 V10 A10 10 0 0 1 20 0 Z" />
<!-- Why you would hand-write that instead of using <rect rx>: it composes with
other path commands in one element, so a single animation or clipPath
applies to the whole shape. -->
pathLength and drawing tricks
<!-- pathLength normalises the measured length of the path, so
stroke-dasharray and stroke-dashoffset can be expressed as fractions
of the total. This is what makes a "draw the line" animation easy. -->
<svg viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
<path d="M10 50 C 60 0, 140 60, 190 10"
fill="none" stroke="#6d28d9" stroke-width="3"
pathLength="1"
stroke-dasharray="1"
stroke-dashoffset="1">
<animate attributeName="stroke-dashoffset" from="1" to="0" dur="1.2s" fill="freeze"/>
</path>
</svg>Full lesson: Paths in depth: commands, curves and arcs →
Text, fonts and text on a path
Font loading and the alternatives
<!-- A web font must be loaded before the SVG renders, or the text reflows
after the fact — and in an <img> or background SVG, the page's fonts are
not available at all. -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<svg viewBox="0 0 200 40" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Embedding a font in the SVG makes the file standalone but huge. -->
<!-- <style>@font-face { font-family: Inter; src: url(data:font/woff2;base64,...); }</style> -->
</defs>
<text x="0" y="24" font-family="Inter, system-ui, sans-serif">Embedded and standalone</text>
</svg>
Font loading and the alternatives
<!-- foreignObject embeds HTML inside SVG. Powerful, and a compatibility trap. -->
<svg viewBox="0 0 300 120" xmlns="http://www.w3.org/2000/svg" width="300" height="120">
<rect x="0" y="0" width="300" height="120" fill="#f8fafc" rx="8"/>
<foreignObject x="12" y="12" width="276" height="96">
<!-- Every element inside must be in the XHTML namespace. -->
<div xmlns="http://www.w3.org/1999/xhtml" style="font:13px system-ui;color:#0f172a">
<p style="margin:0 0 6px;font-weight:600">Rendered as HTML</p>
<p style="margin:0;color:#475569">Reflows, wraps and honours the page's CSS.</p>
</div>
</foreignObject>
</svg>Full lesson: Text, fonts and text on a path →
Filters and visual effects
Cost, alternatives and fallbacks
<!-- If a filter must not recompute on resize, freeze the element's size and
scale the whole thing instead. -->
<svg width="120" height="120" viewBox="0 0 120 120" aria-hidden="true">
<g filter="url(#paper)">
<rect x="0" y="0" width="120" height="120" fill="#f8fafc"/>
</g>
</svg>
<!-- and in CSS scale it, so the filter result is generated once:
.paper-bg { transform: scale(2); transform-origin: 0 0; } -->Full lesson: Filters and visual effects →
Responsive, fluid and data-driven SVG
viewBox, preserveAspectRatio and CSS sizing
<!-- The three attributes that decide how an SVG scales -->
<svg viewBox="0 0 240 120"
preserveAspectRatio="xMidYMid meet"
width="100%" height="100%">
<rect x="0" y="0" width="240" height="120" fill="#eef2ff"/>
</svg>
<!-- meet: the whole graphic fits, letterboxed. The default. -->
<!-- slice: the graphic fills the box, cropped. -->
<!-- none: stretched, aspect ratio destroyed. -->
<!-- xMinYMin / xMidYMid / xMaxYMax and the xMidYMin-style combination
choose which part of the graphic is anchored. -->Full lesson: Responsive, fluid and data-driven SVG →
Symbol sprites, icon systems and reuse
Keeping a set consistent
# A lint pass over an icon directory: catches the mistakes that break a set.
for file in src/icons/*.svg; do
name=$(basename "$file")
grep -q 'viewBox="0 0 24 24"' "$file" || echo "$name: unexpected viewBox"
grep -q 'currentColor' "$file" || echo "$name: no currentColor"
grep -Eq 'fill="#[0-9a-fA-F]{3,6}"' "$file" && echo "$name: hard-coded fill"
grep -Eq 'stroke="#[0-9a-fA-F]{3,6}"' "$file" && echo "$name: hard-coded stroke"
grep -q '<style' "$file" && echo "$name: embedded style block"
grep -q 'id="' "$file" && echo "$name: id that can collide when inlined"
doneFull lesson: Symbol sprites, icon systems and reuse →
Performance, rendering cost and canvas trade-offs
What actually costs time
<!-- Animated geometry: this forces layout on every frame. -->
<rect x="0" y="0" width="10" height="10">
<animate attributeName="width" from="10" to="100" dur="1s" fill="freeze"/>
</rect>
<!-- Animated transform: composited, no layout. -->
<rect x="0" y="0" width="10" height="10" transform="scale(1 1)">
<animateTransform attributeName="transform" type="scale" from="1 1" to="10 1" dur="1s" fill="freeze"/>
</rect>
<!-- The transform version also scales the corner radius and the stroke, which
is often what you actually want for a bar growing from its left edge. -->Full lesson: Performance, rendering cost and canvas trade-offs →
FAQ
Is this SVG cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
HTML CSS JavaScript TypeScript HTML DOM AJAX
Last refreshed 2026-09-27.