HTML <svg> reference Jump to this section

Common attributes Jump to this section

Basic structure Jump to this section

The <svg> element embeds a scalable vector graphic directly in HTML. Unlike <canvas>, every shape is a real DOM element: you can style them with CSS, select them with JavaScript, and they scale to any size without losing quality.

SVG can be used inline (inside HTML), as an <img> src, or as a CSS background-image. Only inline SVG gives full CSS and JavaScript access.

<svg width="200" height="80"
     xmlns="http://www.w3.org/2000/svg">
    <rect x="10" y="10" width="70" height="60"
          rx="6" fill="#3b82f6"/>
    <circle cx="155" cy="40" r="30"
            fill="#10b981"/>
</svg>

SVG element attributes Jump to this section

width and height Jump to this section

Set the rendered size of the SVG element in the page. Accepts CSS length values (px, %, em, etc.) or bare numbers (treated as pixels). When used alongside viewBox, these control the element's footprint while viewBox controls the internal coordinate system.

Omit both to let CSS control the size, which works well for responsive SVGs that already have a viewBox.

<!-- Fixed size -->
<svg width="80" height="80">...</svg>

<!-- Percentage (fills parent) --> <svg width="100%" height="100%">...</svg>

<!-- CSS-controlled (needs viewBox) --> <svg style="width: 100%; max-width: 400px;" viewBox="0 0 400 200">...</svg>

viewBox Jump to this section

Defines the internal coordinate system: viewBox="minX minY width height". This is what makes SVG scalable; you draw in an abstract coordinate space and the browser maps it to whatever size the element is rendered at.

Always add viewBox to icons and illustrations so they scale cleanly at any size.

<!-- Same SVG content, different rendered sizes -->
<!-- viewBox stays the same; width/height change -->

<svg width="60" height="60" viewBox="0 0 100 100"> <!-- Draw in 0-100 coordinate space --> <circle cx="50" cy="50" r="45"/> </svg>

<svg width="120" height="60" viewBox="0 0 100 100"> <!-- Same drawing, stretched to new size --> <circle cx="50" cy="50" r="45"/> </svg>

preserveAspectRatio Jump to this section

Controls how the SVG content is scaled and positioned when the aspect ratio of viewBox doesn't match the element's width/height. Works like CSS object-fit.

Format: preserveAspectRatio="<align> <meetOrSlice>"

<!-- Center and fit (defaul, like object-fit: contain) -->
<svg preserveAspectRatio="xMidYMid meet">...</svg>

<!-- Stretch to fill (like object-fit: fill) -->
<svg preserveAspectRatio="none">...</svg>

<!-- Cover and crop (like object-fit: cover) -->
<svg preserveAspectRatio="xMidYMid slice">...</svg>

<!-- Align top-left -->
<svg preserveAspectRatio="xMinYMin meet">...</svg>

xmlns Jump to this section

The XML namespace. Because SVG is an XML language, the namespace declaration is necessary to differentiate SVG elements (like <a> or <title>) from elements that might have the same name in other XML languages (like HTML's <a> element)

Required when SVG is in a standalone .svg file or needs to be valid XML. When SVG is written directly inside an HTML5 page (inline SVG), the browser already understands it’s SVG, so the xmlns attribute can usually be left out.

<!-- Required in .svg files -->
<svg xmlns="http://www.w3.org/2000/svg">...</svg>

<!-- Optional in inline HTML5 -->
<svg viewBox="0 0 100 100">...</svg>

Accessibility attributes Jump to this section

role and aria-label Jump to this section

<svg> has no implicit ARIA role. For decorative icons, hide with aria-hidden. For meaningful graphics, add role="img" and aria-label.

<!-- Meaningful icon -->
<svg role="img" aria-label="Home"
     viewBox="0 0 24 24">
    <!-- paths -->
</svg>

<!-- Decorative icon (screen readers skip) --> <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"> <!-- paths --> </svg>

<title> and <desc> Jump to this section

The preferred accessible approach for complex SVGs. <title> gives a short name (like alt text); <desc> gives a longer description. Both must be the first children of <svg> or a <g>.

<svg role="img" aria-labelledby="chart-title chart-desc"
     viewBox="0 0 400 200">
    <title id="chart-title">Monthly revenue 2025</title>
    <desc id="chart-desc">
        Bar chart showing revenue growing from $10k in January
        to $45k in June.
    </desc>
    <!-- chart shapes -->
</svg>

aria-hidden Jump to this section

Use on purely decorative SVGs so assistive technologies skip them entirely.

<button>
    <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
        <!-- decorative icon -->
    </svg>
    Save document
</button>

Common attributes Jump to this section

id Jump to this section

Unique identifier. Essential for referencing the SVG from JavaScript and for <use> references.

<svg id="logo" viewBox="0 0 120 40">...</svg>

<!-- Reference a symbol defined elsewhere -->
<svg viewBox="0 0 24 24">
    <use href="#icon-star"/>
</svg>

class Jump to this section

Assigns CSS classes to the SVG element or any child element.

<svg class="icon icon--large" viewBox="0 0 24 24">
    <circle class="icon__dot" cx="12" cy="12" r="10"/>
</svg>

style Jump to this section

Inline CSS. Properties like color, fill, stroke, width, and height can all be applied.

<svg style="width: 100%; color: currentColor;" viewBox="0 0 24 24">
    <!-- fill="currentColor" inherits the CSS color -->
    <path fill="currentColor" d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>

data-* attributes Jump to this section

Custom metadata on the SVG or any child element.

<svg data-icon="star" data-variant="filled" viewBox="0 0 24 24">
    <path data-part="outline" d="..."/>
</svg>

<script>
  const svg = document.querySelector('svg');
  console.log(svg.dataset.icon);    // "star"
  console.log(svg.dataset.variant); // "filled"
</script>

tabindex Jump to this section

Makes the SVG focusable with the keyboard, necessary for interactive SVGs like charts or diagrams.

<svg tabindex="0" role="img" aria-label="Interactive chart"
     viewBox="0 0 400 200">
    <!-- chart -->
</svg>

SVG elements and drawing Jump to this section

Unlike canvas, SVG shapes are declared as XML elements. Every shape is part of the DOM and can be targeted with CSS and JavaScript.

rect Jump to this section

Draws a rectangle. rx and ry add rounded corners.

<!-- Basic rectangle -->
<rect x="10" y="10" width="70" height="60"
      fill="#3b82f6"/>

<!-- Rounded corners --> <rect x="100" y="10" width="90" height="60" rx="12" fill="#10b981"/>

<!-- Outlined rectangle --> <rect x="10" y="10" width="80" height="60" fill="none" stroke="#3b82f6" stroke-width="2"/>

circle and ellipse Jump to this section

<!-- Circle: cx, cy = center; r = radius -->
<circle cx="45" cy="40" r="30"
        fill="#3b82f6"/>

<!-- Ellipse: rx = x-radius, ry = y-radius --> <ellipse cx="145" cy="40" rx="50" ry="28" fill="#10b981"/>

line and polyline Jump to this section

<!-- Single line -->
<line x1="10" y1="10" x2="90" y2="70"
      stroke="#3b82f6" stroke-width="3"
      stroke-linecap="round"/>

<!-- Multi-segment open path --> <polyline points="110,70 130,20 150,50 170,15 190,40" fill="none" stroke="#10b981" stroke-width="2.5" stroke-linejoin="round"/>

polygon Jump to this section

Like <polyline> but the path is automatically closed.

<!-- Triangle -->
<polygon points="50,10 90,80 10,80"
         fill="#3b82f6"/>

<!-- Pentagon --> <polygon points="150,10 185,38 172,78 128,78 115,38" fill="#10b981"/>

path Jump to this section

The most versatile SVG element. The d attribute holds a mini-language of move, line, curve, and arc commands.

<!-- Path commands:
  M x,y   - Move to
  L x,y   - Line to
  H x     - Horizontal line
  V y     - Vertical line
  C x1,y1,x2,y2,x,y - Cubic bezier
  Q x1,y1,x,y       - Quadratic bezier
  A rx,ry,rot,laf,sf,x,y - Arc
  Z       - Close path
  Lowercase = relative, uppercase = absolute
-->

<!-- Open arrow --> <path d="M10 50 L50 10 L90 50" fill="none" stroke="#3b82f6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>

<!-- Curved path --> <path d="M10 80 Q50 10 90 80" fill="none" stroke="#10b981" stroke-width="2.5"/>

text Jump to this section

SVG text is selectable and accessible. Positioning is by baseline by default.

Hello SVG centered text right-aligned
<!-- Basic text -->
<text x="10" y="30"
      font-size="20" font-weight="bold"
      fill="#1f2937">Hello SVG</text>

<!-- Centered text --> <text x="100" y="60" text-anchor="middle" font-size="14" fill="#6b7280"> centered text </text>

<!-- text-anchor: start | middle | end dominant-baseline: auto | middle | hanging -->

Text on a path Jump to this section

Flow text along a curve using <textPath> referencing a <path> defined in <defs>.

Text flowing on a curved path
<defs>
    <path id="curve" d="M20,90 Q100,10 180,90"/>
</defs>

<text font-size="13" fill="#3b82f6"> <textPath href="#curve"> Text flowing on a curved path </textPath> </text>

Gradients Jump to this section

Defined in <defs> and referenced by id.

<defs>
    <linearGradient id="myGrad"
                    x1="0%" y1="0%"
                    x2="100%" y2="0%">
        <stop offset="0%"   stop-color="#3b82f6"/>
        <stop offset="100%" stop-color="#8b5cf6"/>
    </linearGradient>

<radialGradient id="radGrad" cx="50%" cy="50%" r="50%"> <stop offset="0%" stop-color="#fde68a"/> <stop offset="100%" stop-color="#f59e0b"/> </radialGradient> </defs>

<rect fill="url(#myGrad)" .../> <circle fill="url(#radGrad)" .../>

Filters Jump to this section

SVG filters apply effects like blur, drop shadow, and colour manipulation to any element.

<defs>
    <filter id="blurMe">
        <feGaussianBlur stdDeviation="2"/>
    </filter>

<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"> <feDropShadow dx="3" dy="3" stdDeviation="3" flood-color="rgba(0,0,0,0.3)"/> </filter> </defs>

<rect filter="url(#blurMe)" .../> <rect filter="url(#shadow)" .../>

Clip paths and masks Jump to this section

Clip paths hide everything outside a shape. Masks use luminance for semi-transparency.

<defs>
    <clipPath id="myClip">
        <circle cx="50" cy="45" r="35"/>
    </clipPath>
</defs>

<!-- Anything outside the circle is hidden --> <g clip-path="url(#myClip)"> <rect x="0" y="0" width="100" height="90" fill="#3b82f6"/> </g>

<!-- Mask: white = visible, black = invisible --> <defs> <mask id="myMask"> <rect fill="white" width="100%" height="100%"/> <circle cx="50" cy="50" r="30" fill="black"/> </mask> </defs> <rect mask="url(#myMask)" fill="#10b981" width="100" height="100"/>

<g> (grouping elements) Jump to this section

Groups elements so you can apply transforms, styles, and events to them all at once.

<!-- Group with transform and opacity -->
<g transform="translate(10, 10)"
   opacity="0.9">
    <rect width="50" height="50" fill="#3b82f6"/>
    <circle cx="25" cy="25" r="12" fill="white"/>
</g>

<!-- Rotate the whole group --> <g transform="rotate(15, 100, 50)"> <rect .../> <text .../> </g>

<defs> and <use> (reusable shapes) Jump to this section

Define shapes once in <defs>, then stamp them out with <use>.

<defs>
    <!-- Define a reusable shape -->
    <g id="my-icon">
        <circle cx="12" cy="12" r="10"/>
    </g>
</defs>

<!-- Stamp it out multiple times --> <use href="#my-icon" x="0" y="0" fill="blue"/> <use href="#my-icon" x="30" y="0" fill="green"/> <use href="#my-icon" x="60" y="0" fill="red"/>

<symbol> Jump to this section

<symbol> is like <defs> + <g> with its own viewBox. The standard pattern for an SVG icon sprite.

<!-- Define icons (hidden) -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none;">
    <symbol id="icon-check" viewBox="0 0 24 24">
        <polyline points="20 6 9 17 4 12"
                  fill="none" stroke="currentColor"
                  stroke-width="2" stroke-linecap="round"/>
    </symbol>

    <symbol id="icon-close" viewBox="0 0 24 24">
        <line x1="18" y1="6"  x2="6"  y2="18"
              stroke="currentColor" stroke-width="2"/>
        <line x1="6"  y1="6"  x2="18" y2="18"
              stroke="currentColor" stroke-width="2"/>
    </symbol>
</svg>

<!-- Use anywhere in the document -->
<svg width="24" height="24" aria-hidden="true">
    <use href="#icon-check"/>
</svg>

<svg width="24" height="24" aria-hidden="true">
    <use href="#icon-close"/>
</svg>

CSS animations on SVG Jump to this section

SVG elements support CSS transitions and animations.

/* Spin animation */
.spin {
    transform-origin: center;
    animation: spin 2s linear infinite;
}
@keyframes spin {
    to { transform: rotate(360deg); }
}

/* Pulse animation */ .pulse { animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { r: 12; opacity: 1; } 50% { r: 20; opacity: 0.5; } }

/* Dash animation (draws a path) */ .draw { stroke-dasharray: 300; stroke-dashoffset: 300; animation: draw 2s ease forwards; } @keyframes draw { to { stroke-dashoffset: 0; } }

Stroke properties Jump to this section

butt round square dash dot
<!-- stroke-linecap -->
<line stroke-linecap="butt"/>    <!-- default -->
<line stroke-linecap="round"/>
<line stroke-linecap="square"/>

<!-- Dashed lines --> <line stroke-dasharray="8 4"/> <!-- dash gap --> <line stroke-dasharray="2 6"/> <!-- dot gap -->

<!-- Dash animation offset --> <path stroke-dasharray="300" stroke-dashoffset="0"/>

<!-- stroke-linejoin for corners --> <polyline stroke-linejoin="round"/> <!-- miter|round|bevel -->

Transformations Jump to this section

<!-- translate(x, y) -->
<rect transform="translate(20, 5)"/>

<!-- rotate(angle, cx, cy) --> <rect transform="rotate(45, 50, 50)"/>

<!-- scale(sx, sy) --> <rect transform="scale(1.5, 0.5)"/>

<!-- skewX / skewY --> <rect transform="skewX(20)"/>

<!-- Chain transforms (right to left) --> <rect transform="translate(20,5) rotate(20,30,40)"/>

JavaScript patterns Jump to this section

Because SVG shapes are DOM elements, you can create, read, update, and remove them with standard DOM APIs, along with a handful of SVG-specific methods.

Create SVG elements Jump to this section

SVG elements must be created with the SVG namespace.

const SVG_NS = 'http://www.w3.org/2000/svg';

function createCircle(cx, cy, r, fill) { const circle = document.createElementNS(SVG_NS, 'circle'); circle.setAttribute('cx', cx); circle.setAttribute('cy', cy); circle.setAttribute('r', r); circle.setAttribute('fill', fill); return circle; }

function createRect(x, y, w, h, fill) { const rect = document.createElementNS(SVG_NS, 'rect'); rect.setAttribute('x', x); rect.setAttribute('y', y); rect.setAttribute('width', w); rect.setAttribute('height', h); rect.setAttribute('rx', 4); rect.setAttribute('fill', fill); return rect; }

const svg = document.getElementById('my-svg'); svg.appendChild(createCircle(50, 50, 30, '#3b82f6')); svg.appendChild(createRect(100, 20, 60, 40, '#10b981'));

Read and update attributes Jump to this section

Get and set any SVG attribute with getAttribute / setAttribute.

const circle = document.getElementById('my-circle');

// Read attribute const r = circle.getAttribute('r'); const fill = circle.getAttribute('fill');

// Set attribute circle.setAttribute('r', 40); circle.setAttribute('fill', '#10b981'); circle.setAttribute('opacity', 0.5);

// Remove attribute circle.removeAttribute('opacity');

// CSS properties also work via style or classList circle.style.fill = '#3b82f6'; circle.classList.add('active');

Event listeners on shapes Jump to this section

SVG elements support all standard DOM events.

Hover or click a shape
const rect   = document.getElementById('my-rect');
const circle = document.getElementById('my-circle');
const msg    = document.getElementById('msg');

// Click rect.addEventListener('click', () => { msg.textContent = 'Rect clicked!'; });

// Hover circle.addEventListener('mouseenter', () => { circle.setAttribute('r', 36); msg.textContent = 'Circle hovered'; }); circle.addEventListener('mouseleave', () => { circle.setAttribute('r', 30); msg.textContent = ''; });

// Event delegation on the SVG itself svg.addEventListener('click', e => { const target = e.target; if (target.tagName === 'rect') { /* ... */ } });

Animate with CSS transitions Jump to this section

Apply transitions via inline style or a CSS class for smooth attribute changes.

Hover me
/* SVG transforms need these two properties
   for correct transform-origin behaviour */
.shape {
    transform-box: fill-box;
    transform-origin: center;
    transition: fill 0.4s,
                transform 0.4s;
}

.shape:hover { fill: #8b5cf6; transform: rotate(20deg) scale(1.1); }

Animate with JavaScript Jump to this section

Update attributes in a requestAnimationFrame loop.

const circle = document.getElementById('raf-circle');
let animId = null;
let t = 0;

function animate() { t += 0.03; const x = 20 + (t * 40 % 180); const y = 50 + Math.sin(t) * 30;

circle.setAttribute('cx', x.toFixed(1)); circle.setAttribute('cy', y.toFixed(1));

animId = requestAnimationFrame(animate); }

document.getElementById('start').onclick = () => { if (!animId) animId = requestAnimationFrame(animate); };

document.getElementById('stop').onclick = () => { cancelAnimationFrame(animId); animId = null; };

Export SVG as file Jump to this section

Serialize the SVG DOM to a string and download it.

SVG Export
// Export as .svg file
function exportSVG(svgElement, filename = 'image.svg') {
    const serializer = new XMLSerializer();
    let svgStr = serializer.serializeToString(svgElement);

// Ensure xmlns is present if (!svgStr.includes('xmlns=')) { svgStr = svgStr.replace( '<svg', '<svg xmlns="http://www.w3.org/2000/svg"' ); }

const blob = new Blob([svgStr], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); }

// Export as .png via canvas function exportPNG(svgElement, filename = 'image.png') { const serializer = new XMLSerializer(); const svgStr = serializer.serializeToString(svgElement); const blob = new Blob([svgStr], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob);

const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = svgElement.width.baseVal.value; canvas.height = svgElement.height.baseVal.value; canvas.getContext('2d').drawImage(img, 0, 0);

const a = document.createElement('a'); a.download = filename; a.href = canvas.toDataURL('image/png'); a.click(); URL.revokeObjectURL(url); }; img.src = url; }

Get bounding box Jump to this section

Measure the size and position of any SVG element.

const rect   = document.getElementById('my-rect');
const circle = document.getElementById('my-circle');

// getBBox() returns coordinates in the SVG coordinate system
const box = rect.getBBox();
console.log(box.x, box.y, box.width, box.height);

// getBoundingClientRect() returns page coordinates
const pageBox = circle.getBoundingClientRect();
console.log(pageBox.top, pageBox.left);

// Find the centre of an element
function centre(el) {
    const b = el.getBBox();
    return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
}

Hit test with point-in-fill Jump to this section

Check whether a point is inside an SVG shape using isPointInFill.

const svg    = document.querySelector('svg');
const circle = document.getElementById('my-circle');

svg.addEventListener('click', e => {
    const rect = svg.getBoundingClientRect();

    // Create an SVGPoint in the element's coordinate system
    const pt  = svg.createSVGPoint();
    pt.x = e.clientX - rect.left;
    pt.y = e.clientY - rect.top;

    const hit = circle.isPointInFill(pt);
    console.log(hit ? 'Inside circle' : 'Outside circle');
});

Inline SVG icon component pattern Jump to this section

A reusable pattern for injecting icons into HTML pages.

const icons = {
    check: `<polyline points="20 6 9 17 4 12"
                fill="none" stroke="currentColor"
                stroke-width="2" stroke-linecap="round"
                stroke-linejoin="round"/>`,
    close: `<line x1="18" y1="6" x2="6" y2="18"
                stroke="currentColor" stroke-width="2"/>
            <line x1="6" y1="6" x2="18" y2="18"
                stroke="currentColor" stroke-width="2"/>`,
    star:  `<polygon points="12 2 15 9 22 9 17 14 19 21 12 17 5 21 7 14 2 9 9 9"
                fill="currentColor"/>`
};

function icon(name, size = 24, cls = '') {
    return `<svg width="${size}" height="${size}"
                 viewBox="0 0 24 24"
                 class="${cls}"
                 aria-hidden="true"
                 focusable="false">
                ${icons[name] ?? ''}
            </svg>`;
}

// Usage
document.getElementById('save-btn').innerHTML =
    icon('check', 20, 'btn-icon') + ' Save';