Basic shapes

The six primitive SVG shapes and how to fill and stroke them

The six shapes

SVG provides six built-in primitive elements that cover the vast majority of geometric drawing needs. Everything else — complex icons, charts, illustrations — is ultimately composed from these six plus the <path> element (covered next). Start here and the rest of SVG will make sense.

All coordinates are in the SVG's internal coordinate system defined by viewBox. When you write x="10", you mean 10 units in that coordinate space — not pixels. The browser maps those units to actual screen pixels when it renders the SVG at a given display size.

<rect> — rectangles and squares

The <rect> element draws a rectangle. Its four required attributes are x and y (the top-left corner) plus width and height. Add rx and ry to round the corners — a single rx value rounds all four corners equally, like CSS border-radius.

<svg viewBox="0 0 220 100" width="220" height="100" role="img" aria-label="A sharp-cornered red rectangle and a rounded-corner orange rectangle"> <!-- Sharp corners --> <rect x="10" y="20" width="80" height="60" fill="#d6452c" /> <!-- Rounded corners with rx --> <rect x="120" y="20" width="80" height="60" rx="14" fill="#e07b00" /> </svg>

<circle> — circles

A circle is defined by its center point (cx, cy) and its radius (r). The center is the anchor — resizing r grows the circle outward in all directions from that fixed point.

<svg viewBox="0 0 100 100" width="120" height="120" role="img" aria-label="A teal filled circle"> <circle cx="50" cy="50" r="38" fill="#0f766e" /> </svg>

<ellipse> — ellipses

An ellipse is like a circle but with separate horizontal and vertical radii: rx controls the width and ry controls the height. The center is still specified with cx and cy. When rx === ry, an ellipse is identical to a circle.

<svg viewBox="0 0 160 100" width="200" height="125" role="img" aria-label="A wide green ellipse"> <ellipse cx="80" cy="50" rx="68" ry="36" fill="#1f8a4c" /> </svg>

<line> — straight lines

A line connects two points: (x1, y1) to (x2, y2). Lines have no fill area, so a fill attribute has no effect. A line is invisible unless you give it a stroke — without a stroke color and a non-zero stroke-width, the browser draws nothing.

<svg viewBox="0 0 200 80" width="220" height="88" role="img" aria-label="Three lines with different stroke widths"> <line x1="10" y1="20" x2="190" y2="20" stroke="#d6452c" stroke-width="2" /> <line x1="10" y1="40" x2="190" y2="40" stroke="#e07b00" stroke-width="5" /> <line x1="10" y1="62" x2="190" y2="62" stroke="#0f766e" stroke-width="9" /> </svg>

<polyline> — connected line segments

A <polyline> is a series of connected straight line segments. The points attribute is a space- (or comma-) separated list of x,y coordinate pairs. Like <line>, it must have a stroke to be visible. Polylines have a fill area — the space between the first point, the last point, and the line segments. Setting fill="none" gives you a pure multi-segment line.

<svg viewBox="0 0 200 100" width="220" height="110" role="img" aria-label="A zigzag polyline in teal"> <polyline points="10,80 50,20 90,70 130,15 170,60 200,30" fill="none" stroke="#0f766e" stroke-width="3" /> </svg>

<polygon> — closed shapes

A <polygon> works exactly like <polyline> but the browser automatically draws a closing segment from the last point back to the first, forming a closed shape. This makes it ideal for triangles, pentagons, hexagons, and any other regular or irregular closed polygon.

<svg viewBox="0 0 220 110" width="220" height="110" role="img" aria-label="A red triangle and a green hexagon"> <!-- Triangle --> <polygon points="10,95 65,10 120,95" fill="#d6452c" /> <!-- Hexagon --> <polygon points="175,15 210,38 210,75 175,98 140,75 140,38" fill="#1f8a4c" /> </svg>

All six shapes at a glance

Here is a quick reference gallery showing all six primitive shapes side by side:

<rect>
<circle>
<ellipse>
<line>
<polyline>
<polygon>

Fill & stroke

Every SVG shape has two paint layers: the fill (the interior color) and the stroke (the painted border). Both default to their SVG initial values: fill defaults to black, and stroke defaults to none. You override these with presentation attributes directly on the element, or with CSS — they are interchangeable.

Basic fill and stroke attributes

  • fill — interior color. Any CSS color value works: named colors, hex, rgb(), oklch(), none.
  • fill-opacity — 0 (fully transparent) to 1 (fully opaque), independent of the stroke.
  • stroke — outline color. Must be set to something other than none for the outline to appear.
  • stroke-width — thickness of the stroke in viewBox units. Strokes are centered on the shape's edge, so half the width falls inside, half outside.
  • opacity — applies to the whole element (fill + stroke together).
<svg viewBox="0 0 260 100" width="300" height="115" role="img" aria-label="Three rectangles showing fill, stroke, and opacity combinations"> <!-- Solid fill, outlined stroke --> <rect x="10" y="20" width="70" height="60" fill="#d6452c" stroke="#1f8a4c" stroke-width="5" /> <!-- No fill, stroke only --> <rect x="100" y="20" width="70" height="60" fill="none" stroke="#e07b00" stroke-width="4" /> <!-- Semi-transparent fill --> <circle cx="225" cy="50" r="36" fill="#0f766e" fill-opacity="0.4" stroke="#0f766e" stroke-width="3" /> </svg>

Stroke appearance: linecap, linejoin, and dasharray

Three additional attributes let you control exactly how strokes look at their ends and corners:

  • stroke-linecap — shape of the stroke ends for open paths and lines. Options: butt (default, flat at endpoint), round (semicircle beyond endpoint), square (like butt but extended by half the stroke width).
  • stroke-linejoin — shape of corners where two segments meet. Options: miter (default, sharp point), round (rounded corner), bevel (cut corner).
  • stroke-dasharray — a list of dash and gap lengths that creates a dashed or dotted stroke pattern. A single value like 8 creates equal dashes and gaps; two values like 12 4 make 12-unit dashes with 4-unit gaps.
<svg viewBox="0 0 300 140" width="320" height="150" role="img" aria-label="Lines demonstrating stroke-linecap and stroke-linejoin options"> <!-- stroke-linecap comparison --> <line x1="20" y1="20" x2="130" y2="20" stroke="#333" stroke-width="10" stroke-linecap="butt" /> <line x1="20" y1="50" x2="130" y2="50" stroke="#333" stroke-width="10" stroke-linecap="round" /> <line x1="20" y1="80" x2="130" y2="80" stroke="#333" stroke-width="10" stroke-linecap="square" /> <!-- Dashed rect with stroke-linejoin="round" --> <rect x="165" y="20" width="120" height="100" rx="4" fill="none" stroke="#d6452c" stroke-width="4" stroke-dasharray="12 5" stroke-linejoin="round" /> </svg>

Semi-transparent overlapping shapes

Using fill-opacity or opacity on overlapping shapes lets you create layered effects. Note the difference: fill-opacity only makes the fill transparent — the stroke remains fully opaque. Setting opacity on the element affects both fill and stroke together.

<svg viewBox="0 0 180 120" width="200" height="133" role="img" aria-label="Three overlapping semi-transparent circles"> <circle cx="60" cy="55" r="45" fill="#d6452c" fill-opacity="0.65" /> <circle cx="100" cy="55" r="45" fill="#e07b00" fill-opacity="0.65" /> <circle cx="80" cy="82" r="45" fill="#1f8a4c" fill-opacity="0.65" /> </svg>