{"slug": "an-interactive-guide-to-svg-paths", "title": "An Interactive Guide to SVG Paths", "summary": "The article explains that SVG `<path>` elements use a `d` attribute containing sequential drawing commands (like \"M\" for move and \"L\" for line) to create shapes, with each command inheriting its starting position from the previous one. It covers basic commands including Move, Line, and Quadratic Bézier curves, describing how the \"Q\" command creates curves using a starting point, a control point, and an end point. The guide aims to help readers build intuition for working with SVG paths, which are essential for creating curved shapes beyond full ellipses.", "body_md": "[Introduction]\n\nThe SVG `<path>`\n\nelement is notoriously tricky. When I first encountered it, I found it totally inscrutable. Its syntax isn’t *quite* as bad as Regex, but it has the same sort of *“what on earth?”* vibes.\n\nAt the same time, `<path>`\n\nelements are also *incredibly* useful. They’re the only way to create curved shapes in SVG, beyond full ellipses. And once you get the hang of it, they’re actually quite a lot of fun to use!\n\nIn this blog post, we’ll cover all of the basic commands, including the infamous arc command. I’ll help you build an intuition for how they work, and show you some cool stuff you can do with them!\n\n[Link to this heading](#the-basic-idea-1)The basic idea\n\nThe `<path>`\n\nelement is modeled after the “pen” tool in vector graphics software like Illustrator. It allows us to chain a bunch of separate drawing instructions together, like a real-world pen being manipulated across a piece of paper.\n\nLet’s look at a basic example:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 12,4\n      L 4,12\n      M 6,4\n      L 12,4\n      L 12,10\n    \"\n  />\n</svg>\n```\n\nThe `d`\n\nattribute stands for “data”, and we use it to define a set of sequential drawing instructions. The “M” command moves our imaginary pen to a specific point, and the “L” command draws a straight line to a specific point.\n\nHere’s a visualization showing each of these steps:\n\n```\n<svg viewBox=\"0 0 16 16\">  <path    d=\"      M 12,4      L 4,12      M 6,4      L 12,4      L 12,10    \"  /></svg>\n```\n\nIt’s like a recipe. Each letter indicates a new step: chop the carrots, boil the broccoli. The numbers are the *parameters* for that instruction, like arguments passed to a function.\n\n**Each instruction flows into the next.** This is something that really confused me at first. I expected that a “Line” command would take *two* points, a start point and an end point. Instead, it only takes an end point; the start point is inherited from the previous command.\n\n[Link to this heading](#commands-2)Commands\n\nThe SVG `<path>`\n\nelement gives us a set of commands we can use to draw all sorts of shapes. We’ve already seen a couple of them, but let’s go through them here in more detail.\n\n[Link to this heading](#move-3)Move\n\nThe `M`\n\ncommand allows us to pick up and move the metaphorical pen tip to somewhere else on the canvas.\n\n```\n<path d=\"M 10,10\" />\n```\n\nThis command takes two numbers: an X coordinate and a Y coordinate.\n\nIt doesn’t draw anything on its own. You can think of it like lifting the pen up and positioning it, floating a centimeter above the page. We generally use this right before a drawing instruction, so that the thing we draw starts in the right place.\n\n**Every path command we write must start with a Move command.** Otherwise, the browser wouldn’t know where to start our drawing from.\n\n[Link to this heading](#lines-4)Lines\n\nWe can draw straight lines with the `L`\n\ncommand:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 2,2\n      L 14,14\n      M 2,14\n      L 14,2\n    \"\n  />\n</svg>\n```\n\nHere’s a visualization showing this sequence of commands:\n\n```\n<svg viewBox=\"0 0 16 16\">  <path    d=\"      M 2,2      L 14,14      M 2,14      L 14,2    \"  /></svg>\n```\n\n[Link to this heading](#bzier-curves-5)Bézier curves\n\nAnd here we get to the first “path-exclusive” feature!\n\nIf you’ve been working with CSS for a while, you’ve likely used Bézier curves to control the *easing* of your [CSS transitions](/animation/css-transitions/). In SVG, we can create those same swoopy curves, but they’re drawn visually rather than used mathematically.\n\nWe have access to two flavors of Bézier curves in SVG. Let’s look at them each in turn.\n\n[Link to this heading](#quadratic-bzier-curves-6)Quadratic Bézier curves\n\nThe `Q`\n\ncommand lets us render “quadratic” Bézier curves. These are Bézier curves with a single control point.\n\n**Drag the handles to see how this works:Drag the handles to see how this works:Focus one of the handles and use the arrow keys to see how this works:**\n\n```\n<svg viewBox=\"0 0 16 16\">  <path    d=\"      M 2,2      Q 2,14        14,14    \"  /></svg>\n```\n\nQuadratic Bézier curves require three points:\n\n- The starting point, set by the\n*previous*command. - The control point, pulling the line in its direction to create the curve.\n- The end point, where the line ends.\n\nLike we saw with the `L`\n\ncommand, Bézier curves inherit their starting position from the previous command. In this case, the previous command is an `M`\n\n(Move) command to `1, 1`\n\n, but we can also chain Bézier curves after other drawing instructions.\n\n[Link to this heading](#cubic-bzier-curves-7)Cubic Bézier curves\n\nThe `C`\n\ncommand produces a *cubic* Bézier curve. This grants us one more control point to work with:\n\n```\n<svg viewBox=\"0 0 16 16\">  <path    d=\"      M 2,2      C 2,14        14,2        14,14    \"  /></svg>\n```\n\nI remember when I was starting out with SVG, the terms “quadratic” and “cubic” were intimidating. Fortunately, the only thing these terms refer to is the number of control points. Quadratic curves have 1 point, cubic curves have 2.\n\nThere are two reasons to use cubic Bézier curves instead of Quadratic ones:\n\n- Your curve has a bend in it, like an “S” shape. These shapes can’t be represented with only a single control point.\n- You need more precision in how exactly your curve is represented.\n\nSingle-point quadratic curves are great for parabola-type shapes, but we can’t really control how sharp it is. With a cubic Bézier curve, we can tighten the curve by moving the two control points close together:\n\n```\n<svg viewBox=\"0 0 16 16\">  <path    d=\"      M 2,2      C 2,15        1,14        14,14    \"  /></svg>\n```\n\n[Link to this heading](#arcs-8)Arcs\n\nLast but certainly not least, we need to talk about elliptical arcs.\n\n*I’ll warn you right away:* arcs are confusing as heck. It took me a *long* time to really build an intuition for what each parameter does.\n\nHere’s what the syntax looks like:\n\n```\n<path\n  d=\"\n    M [start-x],[start-y]\n    A [rx],[ry] [rotation] [large-arc-flag] [sweep-flag] [end-x],[end-y]\n  \"\n/>\n```\n\nThat’s *a lot* of parameters!\n\n**For this command, I want to do something a bit different.** Let’s set this syntax aside for now. We’re going to focus on the high-level ideas, to understand the surprisingly complex problems that arcs solve. That way, when we come back to the syntax, it should make way more sense.\n\nFirst, the basics: The `A`\n\ncommand allows us to draw an *elliptical* curve between a start point and an end point. Like all path commands, it’s designed to be composable so that we can chain it together with other drawing commands.\n\nHere’s a quick `<path>`\n\ndemo that consists of a Move -> Line -> Arc -> Line combo. **Play with the handles to see how the arc behaves:**\n\nThis is a bit like the `<ellipse>`\n\nSVG element, but instead of drawing an entire oval/circle, we only draw the portion of the ellipse that is required to connect the start and end points.\n\nThis is kinda weird, if we think about it. With `<ellipse>`\n\n, the shape is positioned based on its center point, specified with `cx`\n\n/ `cy`\n\n. This feels mathematically straightforward. If you give me one of those elementary school geometry kits, I could produce a circle using this method: Stick the spike into the center coordinate and spin a full 360°.\n\n**With arcs, though, things are a bit more complicated.** Instead of providing a center point to trace around, we instead provide a start/end point. The browser will have to invent a *hypothetical* ellipse that contains both points somewhere on its circumference.\n\nThis might not sound like a big difference, but it introduces several ambiguities that make things weird / interesting / hard.\n\n[Link to this heading](#ellipse-radius-9)Ellipse radius\n\nIn order to draw an elliptical arc between two points, the browser has to do [a bunch of math(opens in new tab)](https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter) to calculate the *entire* ellipse, so that we can draw the small portion needed to connect the points.\n\nFor example, suppose we had the following arc:\n\nIn order for the browser to draw that little bridge connecting the two points, it first has to calculate a hypothetical ellipse that can work, like this one:\n\nIn this particular case, the hypothetical ellipse is a circle with a radius of 4px in a 16×16 viewBox, but this is something that we can configure!\n\nIn fact, because this is an *elliptical* arc, we can control `rx`\n\nand `ry`\n\nindependently, like we can with `<ellipse>`\n\n:\n\n**Here’s the mental model I like to use for this:** Imagine you have a table with a small hole in it. If you place a golf ball onto that hole, maybe 1/3rd of the ball would sink below the surface of the table.\n\nThe arc traces along the bottom edge of that ball:\n\nIf we swapped out the golf ball for one with a larger radius, like a baseball, then our arc would be shallower, since more of the ball is sitting above the hole:\n\nAnd if we chose an *enormous* ball like a bowling ball, the arc would practically be flat:\n\nTo bring this back to SVGs: when we draw an arc, we need to specify a horizontal radius (`rx`\n\n) and a vertical radius (`ry`\n\n). These values affect the size of the hypothetical ellipse, which in turn affects how deep/shallow the arc is. The smaller the radius, the deeper the arc.\n\n[Link to this heading](#large-vs-small-arcs-10)Large vs small arcs\n\nLet’s suppose we want to draw an arc between these points with a `rx`\n\n/`ry`\n\nof `5`\n\n:\n\nAs we saw above, the browser creates a hypothetical ellipse with the provided radius and finds a way to bridge the gap using it, like this:\n\n**But wait a sec:** there are *two separate paths* we could follow, to get from the start point to the end point. We could take the short route going down, or the long way around, going up.\n\n**Try toggling the “Arc size” to see what I mean:**\n\nYou can also drag the handles around to see how this flag behaves with different gaps.\n\nWhenever two points are connected with a hypothetical ellipse, there are two routes we could take. We can pick which option we want with the “large arc flag” parameter. It’s a binary value: `0`\n\nselects the short path, `1`\n\nselects the longer path.\n\n[Link to this heading](#picking-the-right-ellipse-11)Picking the right ellipse\n\nOnce again, let’s start with a hypothetical scenario about a hypothetical ellipse:\n\nIn this case, the circle’s diameter is *exactly* equal to the gap between points, and so there’s only one possible ellipse that can work in this scenario.\n\n**But check this out:** suppose we increase the radius of this ellipse so that it’s a bit bigger than the gap:\n\nIn this case, there’s actually *two* places I can put this ellipse:\n\nWe can select which ellipse we want to use with the “sweep flag”. Like the large arc flag we saw above, it’s a binary value: `0`\n\nselects the counter-clockwise arc, `1`\n\nselects the clockwise arc.\n\nYou can see the resulting arc here:\n\n[Link to this heading](#rotation-12)Rotation\n\nWe’re almost done, I promise! There’s only one more parameter we need to look at.\n\nThis final parameter, `rotation`\n\n, lets us *rotate* the arc:\n\nMore specifically, this parameter rotates the hypothetical ellipse, and it does this *before* trying to figure out how to connect the two points using this ellipse.\n\nIf your arc is circular (when `rx`\n\nand `ry`\n\nare set to the same value), this property has no effect. This makes sense when we imagine rotating a perfect circle: the rotation is totally invisible.\n\n**Now, I’ll be honest with you:** I don’t think I’ve ever actually used this parameter. 😅\n\nThe main use case I see for this property is to correctly align the ellipse with the rest of the path. So, for example, if we’re drawing a cowboy hat at a 45-degree angle, we can apply the same rotation to the ellipse:\n\nI think the reason I never find myself needing this is that I *wouldn’t* try to draw something at an angle like this. I would prefer to draw it straight-on and then rotate the entire shape using transforms. I suppose this could be useful if our path needed to draw multiple things at different angles, but at that point, I’d prefer to create it using drawing software instead of code.\n\nSo, if your brain is feeling overloaded, feel free to not worry about “rotation”! Set this value to `0`\n\nand ride off into the sunset. 🤠\n\n[Link to this heading](#revisiting-the-syntax-13)Revisiting the syntax\n\nI told you arcs were complicated!\n\nHere’s that syntax we started with. Hopefully, with all this new context, it makes a lot more sense:\n\n```\n<path\n  d=\"\n    M [start-x],[start-y]\n    A [rx],[ry] [rotation] [large-arc-flag] [sweep-flag] [end-x],[end-y]\n  \"\n/>\n```\n\nHere’s a quick cheatsheet of what each parameter does:\n\n- The arc starts where the previous command left off. The arc’s start position is inherited from that previous command.\n`rx`\n\nand`ry`\n\ncontrol the horizontal/vertical radius of the hypothetical ellipse.`rotation`\n\nwill rotate the hypothetical ellipse. Specified in degrees. Leave as 0 for no rotation.`large-arc-flag`\n\nis a binary value that controls whether the arc takes the short path (`0`\n\n) or the long path (`1`\n\n). Has no effect if both paths are the exact same length.`sweep-flag`\n\nis a binary value that controls which ellipse is used. From the start point, we can either go counter-clockwise (`0`\n\n) or clockwise (`1`\n\n).`end-x`\n\nand`end-y`\n\nselects the end point for our arc.\n\n**All of these parameters are required.** Even if you don’t want to rotate your arc, for example, you still need to set rotation to \"0\".\n\nHere’s a playground for you to experiment with these concepts yourself:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 2,2\n      L 5,5\n      A 4,4 0 0 0 11,11\n      L 14,14\n    \"\n  />\n</svg>\n```\n\n[Link to this heading](#animations-14)Animations\n\nAt this point, we’ve covered all of the most important fundamentals of SVG paths. I have a few more useful tidbits to share with you, but first, I want to let you know about a thing I’ve been working on. 😄\n\nIt’s called [Whimsical Animations(opens in new tab)](https://whimsy.joshwcomeau.com/), and it’s a comprehensive interactive course about creating next-level animations and interactions.\n\nThe course is split into four parts, covering a wide range of animation techniques. Part 2 is all about SVG animation. You’ll learn how to animate the paths we’ve been working with in this post, to create wonderful micro-interactions and big splashy effects. If you’re finding this blog post useful, you’ll get *so much* out of the course!\n\n**Registration is now open!** You can find out more here:\n\nIf you’ve ever wondered how I made something on this blog, there’s a very good chance that we cover the underlying techniques in the course. My goal is to share all of my secrets, stuff that took me *years and years* to figure out on my own.\n\n[Link to this heading](#lil-extras-15)Lil’ extras\n\nSVG paths have a few little bits of syntactic sugar, things that make it a bit easier to work with.\n\n[Link to this heading](#closing-paths-16)Closing paths\n\nBy default, paths are open-ended, but we can instruct our path to seal itself up using the `Z`\n\ncommand:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 4,4\n      L 4,12\n      L 12,12\n      Z\n    \"\n  />\n</svg>\n```\n\nThe `Z`\n\ncommand will draw a straight line back to the first point specified by the original `M`\n\ncommand. It’s equivalent, in this case, to `L 4,4`\n\n.\n\n[Link to this heading](#relative-commands-17)Relative commands\n\nIn this blog post, we’ve been using uppercase commands like `L`\n\nand `A`\n\n. Each command has a *lowercase* alternative:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 4,4\n      l 4,8\n      l 4,-8\n    \"\n  />\n</svg>\n```\n\nThe lowercase variants are *relative* commands. Instead of specifying coordinates based on the SVG coordinate system (with `(0, 0)`\n\nbeing in the top-left corner), relative commands are anchored to the previous command’s position.\n\nSo, in the example above, we start by moving to `(4, 4)`\n\n. We then draw a relative line that adds 4px horizontally and 8px vertically. These values are added to the command’s starting position. The ending X value will be 8 (4 + 4), and the ending Y value will be 12 (4 + 8), so this command is equivalent to `L 8,12`\n\n.\n\nSimilarly, negative values move in the opposite direction. The final command is another relative line that adds another 4px to the X coordinate (8 + 4 = 12), but *subtracts* 8 from the Y coordinate (12 - 8 = 4).\n\nRelative commands provide an entirely different mental model for designing paths, and it can be useful for certain kinds of illustrations. It also makes it easier to shift things along as a group:\n\nRelative commands will automatically adapt when their anchor point changes, so we wind up sliding the path around rather than deforming it.\n\nThat said, I don’t *really* find myself doing this much, in practice. Instead, I typically solve this problem with a `transform: translate(x, y)`\n\n, to slide the path around wherever I want.\n\n[Link to this heading](#chained-curves-18)Chained curves\n\nIf you’ve ever tried to chain Bézier curves together, you’ve likely found that it’s challenging to get it to look right:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 4,4\n      Q 4,10\n        8,8\n      Q 14,0\n        12,12\n    \"\n  />\n</svg>\n```\n\nIf you look closely, there’s a visible “elbow” where the two curves connect:\n\nIn order for our Bézier curves to flow well, we need to match the *angles* of subsequent curves, so that the path doesn’t veer off in a new direction. There isn’t any sort of built-in smoothing.\n\nFortunately, there is a handy command that can help:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 16 16\">\n  <path\n    d=\"\n      M 4,4\n      Q 4,10\n        8,8\n      T 12,12\n    \"\n  />\n</svg>\n```\n\nThe `T`\n\ncommand creates a Quadratic Bézier curve, like `Q`\n\n, but it doesn’t take a control point, it *only* accepts an end point. The control point is derived automatically by mirroring the angle, so that our path is smooth and kink-free.\n\nSimilarly, the `S`\n\ncommand creates a *cubic* Bézier curve that omits the first control point. That point will be computed automatically to ensure a smooth curve.\n\nFor example:\n\nCode Playground\n\n```\n<svg viewBox=\"0 0 24 16\">\n  <path\n    d=\"\n      M 0,8\n      C 4,0\n        8,21\n        12,12\n      S 16,16\n        24,8\n    \"\n  />\n</svg>\n```\n\nThis is a useful bit of syntactic sugar because it saves us the trial and error of finding a control point that doesn’t result in an elbow. In practice, though, I generally find myself using vector graphics software if my shape includes many chained curves (like the cloud swoops at the top of this page).\n\nLike so many of my blog posts, this one turned out to be way longer than I originally intended, and yet it still only scratches the surface of what can be done with SVG paths. 😅\n\nMy upcoming animations course goes way deeper. There are videos that really dig into the core mechanics, exercises for you to get some practice, and even a few mini-games. I’ll show you how to use SVG paths to add delightful details to your work. ✨\n\nThe course isn’t released yet, but you can sign up for updates here:\n\n### Last updated on\n\nMay 5th, 2026", "url": "https://wpnews.pro/news/an-interactive-guide-to-svg-paths", "canonical_source": "https://www.joshwcomeau.com/svg/interactive-guide-to-paths/", "published_at": "2025-08-18 13:30:00+00:00", "updated_at": "2026-05-22 14:53:18.744633+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["SVG", "Illustrator"], "alternates": {"html": "https://wpnews.pro/news/an-interactive-guide-to-svg-paths", "markdown": "https://wpnews.pro/news/an-interactive-guide-to-svg-paths.md", "text": "https://wpnews.pro/news/an-interactive-guide-to-svg-paths.txt", "jsonld": "https://wpnews.pro/news/an-interactive-guide-to-svg-paths.jsonld"}}