Basic Shapes
SVG gives you a small kit of primitive shapes. Each has its own tag with coordinates and dimensions as attributes. The viewBox sets the internal coordinate system — unrelated to the rendered pixel size.
HTML
<svg width="320" height="220" viewBox="0 0 320 220">
<!-- RECT: x/y = top-left, rx = corner radius -->
<rect x="20" y="20" width="80" height="80"
fill="#22d3ee" rx="10"/>
<!-- CIRCLE: cx/cy = center, r = radius -->
<circle cx="180" cy="60" r="40" fill="#d946ef"/>
<!-- ELLIPSE: rx/ry = horizontal / vertical radius -->
<ellipse cx="260" cy="60" rx="30" ry="50" fill="#fcd34d"/>
<!-- LINE: x1/y1 to x2/y2, stroke styles the line -->
<line x1="20" y1="160" x2="300" y2="160"
stroke="#ec4899" stroke-width="4" stroke-linecap="round"/>
<!-- stroke-dasharray creates a dashed line -->
<line x1="20" y1="190" x2="300" y2="190"
stroke="#10b981" stroke-width="4"
stroke-dasharray="8 6"/>
</svg>
Paths & Commands
The <path> element can draw any shape at all. It takes a single d attribute made of commands. The important ones: M move, L line, C cubic curve, Q quadratic curve, Z close. Uppercase = absolute coords, lowercase = relative.
HTML
<svg viewBox="0 0 320 220">
<!-- TRIANGLE: Move to (30,180), Line to two more points,
Z closes back to the start -->
<path d="M 30 180 L 80 30 L 130 180 Z"
fill="#22d3ee"/>
<!-- HEART via Cubic Bezier (C) curves -->
<path d="M 200 60
C 200 40, 230 40, 230 65
C 230 40, 260 40, 260 60
C 260 90, 230 110, 230 130
C 230 110, 200 90, 200 60
Z"
fill="#ec4899"/>
<!-- WAVE via Quadratic (Q) + shortcut T -->
<path d="M 30 200 Q 80 160, 130 200 T 230 200 T 290 200"
fill="none" stroke="#fcd34d" stroke-width="4"/>
</svg>
Polygon & Polyline
Easier siblings of <path>. Polygon connects a list of points and closes the shape automatically. Polyline does the same but leaves it open — great for charts and arrows.
HTML
<svg viewBox="0 0 320 200">
<!-- STAR: 10 points around the outline — polygon
connects them all AND closes the shape -->
<polygon
points="80,20 96,68 148,68 106,100 122,148
80,120 38,148 54,100 12,68 64,68"
fill="#fcd34d" stroke="#b45309" stroke-width="2"/>
<!-- ARROW: same idea, different points -->
<polygon points="180,100 240,60 240,90 290,90
290,110 240,110 240,140"
fill="#22d3ee"/>
<!-- POLYLINE: open line — good for line charts -->
<polyline
points="20,190 60,150 100,170 140,120 180,140 220,90"
fill="none" stroke="#ec4899" stroke-width="3"/>
</svg>
SVG Text
Text inside SVG can be filled, stroked, rotated, and even placed along a path. Useful for logos and playful headings where regular HTML text can't bend.
HTML
<svg viewBox="0 0 320 220">
<!-- Outlined text: fill="none" + stroke -->
<text x="160" y="50" text-anchor="middle"
font-family="DM Serif Display, serif" font-size="38"
fill="none" stroke="#22d3ee" stroke-width="1.5">
OUTLINED
</text>
<!-- Gradient-filled text -->
<defs>
<linearGradient id="txtGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<path id="curvy" d="M 30 170 Q 160 120 290 170" fill="none"/>
</defs>
<text x="160" y="100" text-anchor="middle" font-size="34"
fill="url(#txtGrad)">GRADIENT</text>
<!-- TEXT on a PATH -->
<text font-size="22" fill="#fff">
<textPath href="#curvy" startOffset="50%" text-anchor="middle">
along a curve!
</textPath>
</text>
</svg>
Linear Gradient
Gradients in SVG live inside <defs> and get referenced by id. A gradient can be shared across any number of shapes — change the definition once, every shape using it updates.
HTML
<svg viewBox="0 0 320 200">
<defs>
<!-- Top to bottom: x1,y1 → x2,y2 define the direction.
(0,0) is top-left of each shape, (1,1) is bottom-right. -->
<linearGradient id="sunset" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#fcd34d"/>
<stop offset="50%" stop-color="#f43f5e"/>
<stop offset="100%" stop-color="#7e22ce"/>
</linearGradient>
</defs>
<!-- Reuse the same gradient on any shape -->
<rect x="20" y="20" width="130" height="160"
rx="14" fill="url(#sunset)"/>
<circle cx="235" cy="100" r="70" fill="url(#sunset)"/>
</svg>
Radial Gradient
Great for spotlights, soft shadows, and planet/orb effects. The gradient radiates outward from a center point.
HTML
<svg viewBox="0 0 320 220">
<defs>
<!-- cx/cy = where the "light source" is inside the shape
(35% from left, 35% from top = upper-left highlight). -->
<radialGradient id="orb" cx="35%" cy="35%" r="65%">
<stop offset="0%" stop-color="#fff"/>
<stop offset="30%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#0e7490"/>
</radialGradient>
<!-- Flame fades to transparent at the edges -->
<radialGradient id="flame" cx="50%" cy="70%" r="55%">
<stop offset="0%" stop-color="#fef3c7"/>
<stop offset="40%" stop-color="#f97316"/>
<stop offset="100%" stop-color="#7c2d12" stop-opacity="0"/>
</radialGradient>
</defs>
<circle cx="100" cy="110" r="70" fill="url(#orb)"/>
<circle cx="230" cy="110" r="70" fill="url(#flame)"/>
</svg>
CSS Styling & Hover
SVG responds to CSS just like HTML. Fills, strokes, opacity, and transforms can all be transitioned on :hover — ideal for interactive diagrams and playful logos.
hover the blob →
HTML
<svg viewBox="0 0 220 220">
<path class="blob"
d="M 110,10 C 160,10 200,50 210,100
C 220,160 180,210 120,210
C 60,210 10,170 10,110
C 10,60 60,10 110,10 Z"/>
</svg>
Basic Draw Animation
The core trick behind every SVG draw-in effect. Set stroke-dasharray to the length of the stroke. Set stroke-dashoffset to that same length — the dash now covers the stroke, hiding it. Animate the offset down to 0 and the stroke appears to draw itself.
HTML
<svg viewBox="0 0 280 180">
<path class="draw"
d="M 30 100 Q 90 30 150 100 T 250 100"
fill="none" stroke="#22d3ee" stroke-width="4"
stroke-linecap="round"/>
</svg>
Signature Draw
A multi-path signature that draws stroke-by-stroke. Each path has a staggered animation-delay, so they appear to be written one at a time.
HTML
<svg class="sig-draw" viewBox="0 0 320 160">
<path d="M 30 30 L 30 110 Q 30 130 50 130 Q 70 130 70 110"/>
<path d="M 90 95 Q 90 60 120 60 Q 150 60 150 90 L 150 130
M 150 105 Q 130 135 100 130"/>
<path d="M 175 70 L 215 70 L 180 125 L 220 125"/>
<path d="M 235 70 L 280 70 L 240 125 L 285 125"/>
</svg>
Icon Trio — Check, Heart, Star
Three icons that draw themselves in sequence — first the outer ring, then the inner shape. Everything on the page that's a single SVG path can get this treatment. Great for a "success" moment or a delightful loading state.
HTML
<div class="icon-trio">
<svg class="icon-check" viewBox="0 0 100 100">
<circle class="icon-ring" cx="50" cy="50" r="40"/>
<polyline class="icon-shape" points="30,52 45,68 72,38"/>
</svg>
<svg class="icon-heart" viewBox="0 0 100 100">
<circle class="icon-ring" cx="50" cy="50" r="40"/>
<path class="icon-shape" d="M 50 72 C 30 58 22 48 22 38 ..."/>
</svg>
<svg class="icon-star" viewBox="0 0 100 100">
<circle class="icon-ring" cx="50" cy="50" r="40"/>
<polygon class="icon-shape" points="50,25 58,45 ..."/>
</svg>
</div>
Hand Lettering — Letter by Letter
Same trick, one path per letter. Each letter starts hidden and draws in after its predecessor. The effect really feels like someone is writing in real time.
HTML
<svg class="hand-svg" viewBox="0 0 340 120"> <!-- One <path> per letter --> <path class="letter" d="M 25 25 L 25 95 M 25 60 L 60 60 M 60 25 L 60 95"/> <!-- H --> <path class="letter" d="..."/> <!-- e --> <path class="letter" d="..."/> <!-- l --> <path class="letter" d="..."/> <!-- l --> <path class="letter" d="..."/> <!-- o --> <path class="letter" d="..."/> <!-- ! --> </svg>
Looping Draw
Instead of drawing once and stopping, the offset is animated through a full cycle — in from the start, then out the other side. Combined with a soft opacity fade, it looks like an ambient pen tracing the path forever.
HTML
<svg class="loop-draw" viewBox="0 0 300 200">
<path d="M 20 100
C 60 20, 120 20, 150 100
C 180 180, 240 180, 280 100"/>
</svg>
The Whole Thing as One File
Everything above — shapes, gradients, paths, and the self-drawing stroke-dasharray trick — combined into one complete HTML file: an animated SVG "badge" hero that draws itself in. Copy it into a new file called svg-hero.html, open it in a browser, and it just works — no libraries, no build step.
Live preview
Complete HTML — copy this whole file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SVG Self-Drawing Hero</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: radial-gradient(ellipse at top, #14233a, #0a0a12 60%);
color: #e2e8f0;
min-height: 100vh;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
gap: 28px; padding: 40px 20px; text-align: center;
}
h1 { font-size: clamp(1.6rem, 5vw, 2.6rem); color: #fff; }
h1 span { color: #22d3ee; }
p.lead { color: rgba(255,255,255,.55); max-width: 440px; line-height: 1.6; }
/* The shared "draw yourself" recipe:
1. dash covers the whole stroke
2. animate the offset down to 0 */
.draw {
stroke-dasharray: 600;
animation: drawIn 2.4s ease forwards;
}
@keyframes drawIn {
from { stroke-dashoffset: 600; }
to { stroke-dashoffset: 0; }
}
/* The icon ring + check draw in sequence */
.ring { stroke-dasharray: 270; animation: drawRing 1s ease forwards; }
.check { stroke-dasharray: 120; animation: drawCheck .7s ease .9s both; }
@keyframes drawRing { from { stroke-dashoffset: 270; } to { stroke-dashoffset: 0; } }
@keyframes drawCheck { from { stroke-dashoffset: 120; } to { stroke-dashoffset: 0; } }
/* The blob reacts to CSS hover, just like in section 07 */
.blob {
transition: fill .5s ease, transform .5s cubic-bezier(.34,1.56,.64,1);
transform-origin: center; cursor: pointer;
}
.blob:hover { fill: #22d3ee; transform: scale(1.08) rotate(8deg); }
.stage {
display: flex; align-items: center; gap: 40px; flex-wrap: wrap;
justify-content: center;
}
.label {
font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
color: rgba(255,255,255,.4); margin-top: 8px;
}
.item { display: flex; flex-direction: column; align-items: center; }
</style>
</head>
<body>
<h1>Drawn with <span>SVG</span>, animated with CSS</h1>
<p class="lead">Vector graphics that scale forever — and a single
<code>stroke-dasharray</code> trick that makes any path draw itself.</p>
<div class="stage">
<!-- 1. Gradient-filled badge with a self-drawing checkmark -->
<div class="item">
<svg width="160" height="160" viewBox="0 0 100 100">
<defs>
<linearGradient id="badge" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#7e22ce"/>
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#badge)" opacity=".18"/>
<circle class="ring" cx="50" cy="50" r="40"
fill="none" stroke="url(#badge)" stroke-width="4"/>
<polyline class="check" points="32,52 45,66 70,36"
fill="none" stroke="#22d3ee" stroke-width="5"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="label">draws itself</span>
</div>
<!-- 2. A self-drawing wave (path + dashoffset) -->
<div class="item">
<svg width="200" height="160" viewBox="0 0 200 160">
<path class="draw"
d="M 20 90 Q 60 20 100 90 T 180 90"
fill="none" stroke="#ec4899" stroke-width="5"
stroke-linecap="round"/>
</svg>
<span class="label">stroke-dasharray wave</span>
</div>
<!-- 3. A hover-reactive blob (CSS on SVG) -->
<div class="item">
<svg width="150" height="150" viewBox="0 0 220 220">
<path class="blob" fill="#fcd34d"
d="M 110,10 C 160,10 200,50 210,100
C 220,160 180,210 120,210
C 60,210 10,170 10,110
C 10,60 60,10 110,10 Z"/>
</svg>
<span class="label">hover me</span>
</div>
</div>
<script>
/* Replay the draw animations on click anywhere on the page.
Removing + re-adding the class restarts the CSS animation. */
document.body.addEventListener('click', function (e) {
if (e.target.closest('.blob')) return; /* let the blob do its own thing */
document.querySelectorAll('.draw, .ring, .check').forEach(function (el) {
var anim = el.style.animation;
el.style.animation = 'none';
void el.offsetWidth; /* force reflow so it replays */
el.style.animation = '';
});
});
</script>
</body>
</html>