SVGSVGElement: the JavaScript object behind the svg tag

SVGSVGElement is the DOM interface that every inline svg element in an HTML page implements. It is part of the browser, not a library, and it is where you read the size, convert click positions and control animation.

SVGSVGElement is the JavaScript interface behind the <svg> tag. This guide uses the web-platform meaning: the DOM object you get when you select an inline <svg> in an HTML page, not a library.

It is the page's handle on a drawing. Read its size, find parts of it, convert click positions and control its animation.

Try it first. The page below holds one <svg>. The buttons change its viewBox and one colour, and the readout is read live from the object.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SVGSVGElement basics</title>
<style>
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  svg { display: block; max-width: 100%; height: auto; background: #fff; border: 1px solid #d5d9e0; border-radius: 10px; }
  .row { margin: 10px 0; display: flex; gap: 8px; flex-wrap: wrap; }
  button { font: inherit; padding: 8px 12px; border: 1px solid #c9ced8; border-radius: 8px; background: #fff; cursor: pointer; }
  pre { margin: 0; padding: 10px 12px; background: #1d2330; color: #d8e1f0; border-radius: 10px; font: 12.5px/1.6 ui-monospace, Consolas, monospace; white-space: pre-wrap; }
</style>
</head>
<body>
<svg id="art" width="300" height="150" viewBox="0 0 300 150">
  <rect x="0" y="0" width="300" height="150" fill="#eef4ff"/>
  <circle id="dot" cx="90" cy="75" r="36" fill="#2563eb"/>
  <rect x="170" y="45" width="90" height="60" rx="8" fill="#16a34a"/>
</svg>

<div class="row">
  <button id="zoom">Zoom in (viewBox 150 x 75)</button>
  <button id="reset">Reset</button>
  <button id="color">Recolour the circle</button>
</div>

<pre id="out"></pre>

<script>
  // querySelector('svg') returns an SVGSVGElement
  const svg = document.querySelector('svg');
  const out = document.getElementById('out');

  function show() {
    out.textContent =
      'svg instanceof SVGSVGElement: ' + (svg instanceof SVGSVGElement) + '\n' +
      'svg.width.baseVal.value:      ' + svg.width.baseVal.value + '\n' +
      'svg.viewBox.baseVal.width:    ' + svg.viewBox.baseVal.width + '\n' +
      'svg.viewBox.baseVal.height:   ' + svg.viewBox.baseVal.height;
  }

  // viewBox is read-only: change the attribute, then read baseVal again
  document.getElementById('zoom').addEventListener('click', () => {
    svg.setAttribute('viewBox', '0 0 150 75');
    show();
  });
  document.getElementById('reset').addEventListener('click', () => {
    svg.setAttribute('viewBox', '0 0 300 150');
    show();
  });

  // getElementById on the svg searches inside that svg
  let on = false;
  document.getElementById('color').addEventListener('click', () => {
    on = !on;
    svg.getElementById('dot').setAttribute('fill', on ? '#dc2626' : '#2563eb');
  });

  show();
</script>
</body>
</html>
Select the svg, check its type, read width and viewBox, then change the view and one colour.

The steps behind that demo:

  1. Write the <svg> inline in the page and give it an id.
  2. Select it with document.querySelector('svg') or getElementById.
  3. Read sizes through baseVal, not as plain numbers.
  4. Change things with setAttribute, then read the property again.

For the tag itself, see SVG in HTML and the svg tag.

What the interface gives you

The object keeps everything an element has, and adds the svg extras. MDN lists the inheritance chain as shown here.

An svg tag in the HTML becomes an SVGSVGElement, which extends SVGGraphicsElement and the generic element types.
An svg tag in the HTML becomes an SVGSVGElement, which extends SVGGraphicsElement and the generic element types.

That means addEventListener, setAttribute and querySelector all work on it. Selecting elements with querySelector and the DOM in JavaScript cover those.

The members that are specific to svg fall into four groups.

The members of SVGSVGElement in four groups, plus the ones MDN marks deprecated or legacy.
The members of SVGSVGElement in four groups, plus the ones MDN marks deprecated or legacy.
Member What MDN says it does
viewBox Returns an SVGAnimatedRect for the viewBox attribute
width, height Return an SVGAnimatedLength for the attribute
createSVGPoint() Creates a DOMPoint at (0,0), outside any document tree
getElementById() Searches the svg for an element with that id
pauseAnimations() Pauses all running animations in the svg
setCurrentTime() Sets the svg's animation clock, in seconds
currentScale Scale factor of the outermost svg, writable

MDN marks suspendRedraw(), forceRedraw(), useCurrentView, currentView and the ...ToMillimeter properties as deprecated or legacy. Leave them out of new code.

Read sizes through baseVal

The first surprise: svg.width is not a number. It is an SVGAnimatedLength, an object with a read-only baseVal and a read-only animVal. animVal equals baseVal unless the attribute is being animated.

The number is one level further down:

const svg = document.querySelector('svg');
svg.width.baseVal.value;      // 300, in user units
svg.viewBox.baseVal.width;    // width of the viewBox

viewBox works the same way. It is read-only, so svg.viewBox = '0 0 10 10' changes nothing. Call setAttribute('viewBox', ...) and read baseVal again, as the first demo does.

Turn a click into SVG coordinates

A click gives you pixels. Shapes inside the svg live in user units, the coordinates of the viewBox. When the svg is scaled to fit its container, the two differ, and using pixels as units puts the mark in the wrong place.

A 200px board with a viewBox 100 units wide: pixel 120 is unit 60, not unit 120.
A 200px board with a viewBox 100 units wide: pixel 120 is unit 60, not unit 120.

The svg can do the conversion. Make a point with createSVGPoint(), fill in the pixel position, and run it through the inverse of getScreenCTM():

const pt = svg.createSVGPoint();   // a DOMPoint at 0,0
pt.x = e.clientX;
pt.y = e.clientY;
const p = pt.matrixTransform(svg.getScreenCTM().inverse());
// p.x and p.y are now in user units

getScreenCTM() returns a DOMMatrix, inverse() returns a new matrix and leaves the original alone, and matrixTransform() returns a new point. At any svg size, the green mark in the next demo lands under the pointer.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Click position to SVG coordinates</title>
<style>
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  svg { display: block; width: 100%; max-width: 520px; height: auto; background: #fff; border: 1px solid #d5d9e0; border-radius: 10px; cursor: crosshair; }
  .legend { margin: 10px 0 6px; font-size: 14px; }
  .g { color: #15803d; font-weight: 700; }
  .o { color: #c2410c; font-weight: 700; }
  pre { margin: 8px 0 0; padding: 10px 12px; background: #1d2330; color: #d8e1f0; border-radius: 10px; font: 12.5px/1.6 ui-monospace, Consolas, monospace; white-space: pre-wrap; }
  button { font: inherit; padding: 6px 12px; border: 1px solid #c9ced8; border-radius: 8px; background: #fff; cursor: pointer; }
</style>
</head>
<body>
<svg id="board" viewBox="0 0 100 50">
  <path d="M0 25H100M50 0V50" stroke="#e1e4ea" stroke-width=".5"/>
  <g id="marks"></g>
</svg>

<p class="legend"><span class="g">Green</span> = converted with getScreenCTM().
<span class="o">Orange ring</span> = pixels used as units.</p>
<button id="clear">Clear</button>
<pre id="out">Click or tap the board.</pre>

<script>
  const svg = document.getElementById('board');
  const marks = document.getElementById('marks');
  const out = document.getElementById('out');
  const NS = 'http://www.w3.org/2000/svg';

  function dot(x, y, attrs) {
    const c = document.createElementNS(NS, 'circle');
    c.setAttribute('cx', x);
    c.setAttribute('cy', y);
    c.setAttribute('r', 2);
    c.setAttribute('pointer-events', 'none');
    for (const k in attrs) c.setAttribute(k, attrs[k]);
    marks.appendChild(c);
  }

  svg.addEventListener('click', (e) => {
    // 1) a point object from the svg, filled with screen pixels
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    // 2) the inverse of getScreenCTM() turns pixels into user units
    const p = pt.matrixTransform(svg.getScreenCTM().inverse());

    // the common mistake: pixels relative to the svg, used as units
    const r = svg.getBoundingClientRect();
    const px = e.clientX - r.left, py = e.clientY - r.top;

    dot(p.x, p.y, { fill: '#16a34a' });
    dot(px, py, { fill: 'none', stroke: '#ea580c', 'stroke-width': 0.6 });

    out.textContent =
      'pixels in svg: ' + px.toFixed(0) + ', ' + py.toFixed(0) + '\n' +
      'user units:    ' + p.x.toFixed(1) + ', ' + p.y.toFixed(1) + '\n' +
      'svg width now: ' + r.width.toFixed(0) + 'px for a viewBox 100 wide';
  });

  document.getElementById('clear').addEventListener('click', () => {
    marks.innerHTML = '';
    out.textContent = 'Click or tap the board.';
  });
</script>
</body>
</html>
Click the board. Green is converted with the inverse matrix. The orange ring uses pixels as units.

You can run the same conversion inside a pointer event handler: see JavaScript pointer events.

Pause and seek animations

SVG can animate itself with elements such as <animate> and <animateTransform>. The svg element owns the clock for those. pauseAnimations() stops it, unpauseAnimations() resumes it, and setCurrentTime() jumps to a time in seconds.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SVG animation clock</title>
<style>
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  svg { display: block; width: 100%; max-width: 520px; height: auto; background: #fff; border: 1px solid #d5d9e0; border-radius: 10px; }
  .row { margin: 10px 0; display: flex; gap: 8px; flex-wrap: wrap; }
  button { font: inherit; padding: 8px 12px; border: 1px solid #c9ced8; border-radius: 8px; background: #fff; cursor: pointer; }
  pre { margin: 0; padding: 10px 12px; background: #1d2330; color: #d8e1f0; border-radius: 10px; font: 12.5px/1.6 ui-monospace, Consolas, monospace; }
</style>
</head>
<body>
<svg id="stage" viewBox="0 0 200 70">
  <circle cx="20" cy="22" r="10" fill="#2563eb">
    <animate attributeName="cx" values="20;180;20" dur="4s" repeatCount="indefinite"/>
  </circle>
  <rect x="85" y="40" width="30" height="22" rx="4" fill="#16a34a">
    <animateTransform attributeName="transform" type="rotate" from="0 100 51" to="360 100 51" dur="3s" repeatCount="indefinite"/>
  </rect>
</svg>

<div class="row">
  <button id="pause">pauseAnimations()</button>
  <button id="resume">unpauseAnimations()</button>
  <button id="rewind">setCurrentTime(0)</button>
</div>

<pre id="out"></pre>

<script>
  const svg = document.getElementById('stage');
  const out = document.getElementById('out');

  document.getElementById('pause').addEventListener('click', () => svg.pauseAnimations());
  document.getElementById('resume').addEventListener('click', () => svg.unpauseAnimations());
  document.getElementById('rewind').addEventListener('click', () => svg.setCurrentTime(0));

  // read the svg's own animation clock a few times a second
  setInterval(() => {
    out.textContent =
      'getCurrentTime():   ' + svg.getCurrentTime().toFixed(1) + ' s\n' +
      'animationsPaused(): ' + svg.animationsPaused();
  }, 100);
</script>
</body>
</html>
Pause, resume or rewind the svg's own clock. The readout comes from getCurrentTime and animationsPaused.

MDN describes these methods for SVG's own animations, the ones written with <animate>, <animateMotion> and <animateTransform>.

Create an svg from script

To build a drawing from JavaScript, use createElementNS with the SVG namespace. MDN notes that createElement('svg') returns an HTMLUnknownElement, and the drawing is not rendered.

const NS = 'http://www.w3.org/2000/svg';
const svg = document.createElementNS(NS, 'svg');
svg.setAttribute('viewBox', '0 0 100 50');
const c = document.createElementNS(NS, 'circle');
c.setAttribute('cx', 50);
c.setAttribute('cy', 25);
c.setAttribute('r', 20);
svg.appendChild(c);
document.body.appendChild(svg);

The click demo uses the same call to add its marks. To make an svg fit its container, see scaling an SVG to fit.

When it does not work

Symptom Cause Fix
svg.width prints an object It is an SVGAnimatedLength Use svg.width.baseVal.value
Assigning to svg.viewBox does nothing viewBox is read-only Call setAttribute('viewBox', ...)
A script-made svg never shows Made with createElement Use createElementNS and the SVG namespace
Clicks land in the wrong spot Pixels used as user units Convert with the inverse of getScreenCTM()
currentScale has no effect The svg is not outermost MDN: it is always 1 on nested svg
pauseAnimations() seems ignored The motion is not made with animate elements MDN describes it for those elements only; pause other motion its own way
querySelector returns the wrong svg Several svgs on the page Give each an id and select by id

An svg that reacts to clicks is hard to judge from a screenshot, and an .html attachment may open as plain code on a phone. Send the working page instead.

Paste the page into a NOS document and choose Create share link. HTML to link walks through it.

The page renders as written and its scripts run, so the people you send it to can click the board and pause the animation themselves. If you change the code later, the same link shows the new version.

Questions people ask

What is SVGSVGElement?

The interface that represents an svg element in the DOM. MDN describes it as providing access to the properties of svg elements, plus methods to manipulate them and some utility methods such as matrix operations.

How do I get an SVGSVGElement in JavaScript?

Select the inline svg tag the same way as any element, for example with document.querySelector("svg") or getElementById on its id. The object you get is an SVGSVGElement.

Why does svg.width not give me a number?

On an SVGSVGElement, width is an SVGAnimatedLength, not a number. Read svg.width.baseVal.value for the width in user units.

Can I assign to svg.viewBox?

No. MDN lists viewBox as read-only and it returns an SVGAnimatedRect. To change the view, call setAttribute("viewBox", "0 0 150 75") and read svg.viewBox.baseVal afterwards.

Which browsers support it?

MDN marks SVGSVGElement as widely available, supported across browsers since July 2015, and adds that some parts of the feature may have varying levels of support. Check the MDN page of a single member before relying on it.

Keep reading