---
title: "Shapes"
description: "A SwiftUI shape draws a path within its given bounds."
url: https://www.swiftuifieldguide.com/layout/shape
markdown_url: https://www.swiftuifieldguide.com/layout/shape.md
---
> Convenience Markdown export of the HTML page. Interactive samples, diagrams, and visualizations stay on the canonical page.
# Shapes

Most built-in shapes in SwiftUI accept their proposed size and fill the proposed size. `Circle` is the exception; it'll always report a square size. We can see the reported sizes in the sample below by enabling the border, which visualizes the shape's bounding box.

> Pretty-printed code from Basic

```txt
Rectangle()
    .fill(Color.accentColor)
    /* .border(.red) */
```

> Interactive example on HTML page: Basic.

By default, a shape gets filled using the current foreground style. We can either use `fill` (as we did in the example above) or add a `stroke` to the shape. A stroke traces the shape, drawing half of the line width outside of the bounds (we can visualize the bounds by enabling the border).

> Pretty-printed code from Stroke

```txt
RoundedRectangle(cornerRadius: 10)
    .stroke(Color.accentColor, lineWidth: )
    /* .border(.red) */
```

> Interactive example on HTML page: Stroke.

## Insettable Shapes {#insettable}

When we have an insettable shape, we can use `strokeBorder` to draw the stroke inside the bounds of the shape.

## Custom Shapes {#customShapes}

We can also define our own custom shapes. In essence, a shape is a wrapper around a `Path` — but it takes into account the proposed size. For example, we can write a shape that displays a checkmark sign. By using properties such as `maxX` instead of hard coded values, the path always fits exactly inside the proposed rectangle:

> Pretty-printed code from Custom Shape Code

```swift
struct Checkmark: Shape {
    func path(in rect: CGRect) -> Path {
        Path { p in
            p.move(to: .init(x: rect.minX,
                             y: rect.midY))
            p.addLine(to: .init(x: rect.minX
                                    +
                                    rect.size.width
                                        /
                                        3,
                                y: rect.maxY))
            p.addLine(to: .init(x: rect.maxX,
                                y: rect.minY))
        }
    }
}
```

> Interactive example on HTML page: Custom Shape Code.

We can now use our shape as any other shape, for example by applying a stroke:

> Pretty-printed code from Custom Shape

```txt
Checkmark()
    .stroke(Color.accentColor, lineWidth: )
    /* .border(.red) */
    .padding()
```

> Interactive example on HTML page: Custom Shape.

When we adjust the size of the frame above, the path of the shape fits exactly inside the rectangle (even when the stroke might draw outside). However, our custom shape does look distorted when it's not drawing within a square. We can enforce a square aspect ratio by returning a square size in the `sizeThatFits` method:

> Pretty-printed code from Custom Shape Code

```swift
struct Checkmark: Shape {
    func path(in rect: CGRect) -> Path {
        Path { p in
            p.move(to: .init(x: rect.minX,
                             y: rect.midY))
            p.addLine(to: .init(x: rect.minX
                                    +
                                    rect.size.width
                                        /
                                        3,
                                y: rect.maxY))
            p.addLine(to: .init(x: rect.maxX,
                                y: rect.minY))
        }
    }
}
```

> Interactive example on HTML page: Custom Shape Code.

Now our shape always renders with a square aspect ratio, regardless of the size we propose:

> Pretty-printed code from Custom Shape

```txt
Checkmark()
    .stroke(Color.accentColor, lineWidth: )
    /* .border(.red) */
    .padding()
```

> Interactive example on HTML page: Custom Shape.

When we want more control over how the end points are drawn within a stroked shape, we can specify the line cap parameter using a custom stroke style. Likewise, we can specify the line join parameter to control the appearance of the line connections. The example below lets us tweak both parameters:

> Pretty-printed code from Stroke Style Sample

```txt
Checkmark()
    .stroke(Color.accentColor,
            style: StrokeStyle(lineWidth: ,
                               lineCap: .round,
                               lineJoin: .round))
    /* .border(.red) */
    .padding(30)
```

> Interactive example on HTML page: Stroke Style Sample.
