Swiftpack.co - Package - CodeSlicing/pure-swift-ui
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.

PureSwiftUI is a Swift package designed to enhance the experience of writing SwiftUI code. An additional goal is to make these changes as intuitive as possible, requiring little to no experience with the package to begin using its advantages in ernest.


We all love SwiftUI, and what the engineers at Apple have achieved is nothing short of ground-breaking. Often, however, a View can become cluttered with argument labels, type coercion, and various other aspects of day-to-day View creation that tend to get in the way of the design. With SwiftUI being a design language as much as anything else, PureSwiftUI was created to remove as much code external to intent as possible while retaining the expressiveness of the base API. As someone who exclusively writes views in code, a secondary consideration was to reduce the amount of typing as much as possible.


To demonstrate some of the advantages, let's say you want to generate the following label:

Label with white text and a red background and rounded corners rotated slightly clockwise

The code below shows how you would generate this label, including a small offset, comparing the native SwiftUI code to that of PureSwiftUI.


private let width: Double = 200
private let height: Int = 100
private let xOffset: Int = 10
private let yOffset: Double = 10
private let rotation: Int = 20
private let scale: Double = 1.1
private let opacity: Float = 0.9


// native SwiftUI

    .frame(width: CGFloat(width), height: height)
    .overlay(Capsule().stroke(Color.black, lineWidth: 4))
    .offset(x: CGFloat(xOffset), y: CGFloat(yOffset))

// with PureSwiftUI

TitleText("PureSwiftUI", .white, .bold)
    .frame(width, height)
    .clipCapsuleWithStroke(.black, lineWidth: 4, fill: Color.red)
    .offset(xOffset, yOffset)

As you can see the difference is dramatic, favouring design over implementation boiler-plate.

Intention Focused Modifiers

As shown in the previous example, by removing many of the explicit argument labels, the clarity of the code is increased. In most cases the modifier name is expressive enough to document the code without needing argument labels. Including them, in my opinion, only reduces readability.

Since these modifiers are used frequently by even casual coders, it's reasonable to assume that familiarity with how they behave is more than enough to bridge any reduction in auto-documentation.

For example, if you only want to set the width and offset something horizontally you would do this in SwiftUI natively:

.frame(width: 100)
.offset(x: 50)

With argument labels, about a third of this code could be considered noise. In addition, you're calling the frame modifier, but you only want to set the width. PureSwiftUI tackles this in the following way:


Another area that is improved is for components that don't expand to fill all available space by default; Text is a good example of this. Ordinarily you would achieve this like so:

Text("Some expanding text")
    .frame(maxWidth: .infinity, maxHeight: .infinity)

This is accomplished in the following way in PureSwiftUI:

Text("Some expanding text")
    .greedyFrame() // or .greedyWidth / .greedyHeight

which I believe is a clearer expression of the intent.

Simplified Common Usage

Image Resizing

When using images we almost always set the image to resizable, then we set the scaling aspect ratio followed by the frame size. PureSwiftUI packages this into one simple yet descriptive modifier:

// native SwiftUI
    .scaledToFill() // or scaledToFit
    .frame(width: 200, height: 100)

// with PureSwiftUI
    .resizedToFill(200, 100) // or resizedToFit

Clip Shapes and Strokes

Now I realise that clipping a shape is no great hardship. However, providing dedicated modifiers for each shape also allows for the content to be matched to that shape. In other words by using a specific clip shape modifier you don't need to restrain the content in a separate step (This can be set to unconstrained if required).

So the following code achieves the same result:

// native SwiftUI
.clipShape(RoundedRectangle(cornerRadius: 10))
.contentShape(RoundedRectangle(cornerRadius: 10))

// with PureSwiftUI

Going further, stroking and filling shapes is a regular operation that results in rather obfuscated code once again detracting from the intent: to create a stroked shape. Going back to the example from the tl;dr section, if you ignore the transformative modifiers and just look at the styling, you can see what a difference it can make:

... properties

// native SwiftUI
    .frame(width: CGFloat(width), height: CGFloat(height))
    .overlay(Capsule().stroke(Color.black, lineWidth: 4))

// with PureSwiftUI
TitleText("PureSwiftUI", .white, .bold)
    .frame(width, height)
    .clipCapsuleWithStroke(.black, lineWidth: 4, fill: Color.red)

Not only is the code more understandable, but it's also a lot quicker to write!


Frame is a concept in PureSwiftUI that embodies a region of a certain size. Oftentimes we find ourselves writing some styling code for a simple RoundedRectangle with a blue background color in one variation of the following:

// native SwiftUI
    .frame(width: 100, height: 60)

    .frame(width: 100, height: 60)

    .frame(width: 100, height: 60)

So far so normal. But all we want is a frame of a certain size, and this inconsistency betrays the intention. Is it a Rectangle? A Color? A Spacer? No, it's just a frame, so for this kind of scenario - and it comes up a lot - you can simply use Frame like so:

Frame(100, 60, .blue)

The same argument types can be passed to Frame that can be passed to the frame modifier extensions so it's extremely flexible, descriptive, and concise.

Type Coercion

Coercing variables can also lead to obfuscated design. In many common use-cases, with PureSwiftUI you don’t have to worry about passing specifically typed parameters. As long as your variable is an Int, Double, Float, or CGFloat, you’re fine. In most cases you can mix types in the same modifier.

let width: Double = 200
let height = 100


// native SwiftUI
.frame(width: CGFloat(width), height: CGFloat(height))

// PureSwiftUI
.frame(width, height)

Navigating Coordinate Spaces

GeometryReader Modifier

A common issue when using GeometryReader is that it is a view that will grab all available space in the parent, much like Color. This means when we wrap a View or element that takes up less space than is offered by the parent in a GeometryReader we essentially change the layout which of course is undesirable.

The PureSwiftUI answer to this problem is the geometryReader modifier that calls back with the same GeometryProxy object that can be probed for sizing or location information specifically for the view in question without affecting the layout, like so:

Text("What's my size?")
    .geometryReader {(geo: GeometryProxy) in

As an aside, there are numerous GeometryProxy extensions in PureSwiftUI giving access to the various local or global frames for convenience.

The ability to constrain GeometryReader in this way is utilised to provide some powerful modifiers.

Offsets and Absolute Positioning

While you can of course position elements to your heart's desire, this will fundamentally change the layout of the View in question. On top of that, you cannot conditionally place something, since the position modifier requires a default value to fall back on, which would be the original position of the View. You can obtain this using the geometryReader, but there's a problem. By manually setting the position, the origin changes!

To combat this problem, PureSwiftUI offers the offsetToPosition modifier allowing you to set the position of a View to an absolute position within any coordinate space without the need to know anything about the current position or size of the View you're offsetting. There are of course extensions for conditional flavours of this modifier as well as restricting the movement to the x or y axis.

Additionally you are able to specify an anchor to which to apply the positional offset. If I wanted to conditionally place the bottom trailing corner of my View to the origin of a namespace called "outer" I would only have to do the following:

    .offsetToPositionIf(condition, 0, 0, in: "outer", anchor: .bottomTrailing)

In this example, I'm conditionally offsetting the position of the dialer buttons to the position of the phone toggle button:

You can find a gist for this here but the important bit is:

    .offsetToPositionIfNot(showingDialer, phoneButtonPosition)

Since there's no need to perform any offset calculations, I can simply arrange the dialer buttons how I would do normally, and offset them when required.

Another helpful extension is the relativeOffset modifier and the various related signatures. This facilitates offsetting Views based on the size of the View being offset. So you specify a fraction, and the appropriate offset is applied.

In the following example, I'm offsetting each of the four blue rectangles by 80% of their respective widths of heights:

The gist is here but the relevant code is as follows:

Frame(boxSize / 2, boxSize, .blue)
    .relativeXOffsetIf(self.open, 0.8)

These modifiers remove the need to externalize any offset vs positional calculations keeping the intent of the code clean and free from distraction.

Conditional Modifiers

With liberal use of the ternary operator it is of course possible to conditionally style components based on the current state, but oftentimes the default value of the modifier is used as the off state. In other words, keeping the default value as part of the display logic only serves to distract from the intent.

Consider the following example that sets the opacity of a component depending on whether or not it is disabled:

@State private var disabled = false


.opacity(disabled ? 0.4 : 1)

Standard right? However, since the enabled state reverts to the default value for opacity this code explicitly includes a redundant else clause and is the semantic equivalent to the following:

if disabled {
    opacity = 0.4
} else {
    // do nothing

This isn't something we would reasonably do in non-SwiftUI code, and obscures the important part: that opacity is only modified in the disabled state. PureSwiftUI avoids this predicament by providing conditional modifiers, so the previous code-block would be written in this way:

@State private var disabled = false


.opacityIf(disabled, 0.4)

We therefore avoid unnecessary references to default values and reduce friction to understanding the purpose of the code. It is also fully animatable, so you don't lose anything but baggage. In addition, since the ! operator can be easy to miss, modifiers are provided for the negative case, like so:

@State private var enabled = false


.opacityIfNot(enabled, 0.4)

// vs natively
.opacity(!enabled ? 0.4 : 1)

.opacity(enabled ? 1 : 0.4)

There are a number of conditional modifiers to explore; just type .if and see what comes up.

An example here can show how PureSwiftUI can have a huge impact on both code-clarity and efficiency. Imagine we wanted to produce the following rather contrived example:

The code for doing that is shown below in both native SwiftUI and PureSwiftUI styles:

// native SwiftUI
    .frame(width: modified ? 200 : 50, height: modified ? 100 : 50)
    .overlay(RoundedRectangle(25).stroke(Color.black, lineWidth: 5))
    .rotationEffect(.degrees(modified ? 180 : 0))
    .offset(y: modified ? 100 : 0)
    .hueRotation(.degrees(modified ? 360 : 0))
    .opacity(modified ? 0.5 : 1)

// with PureSwiftUI
    .frameIf(modified, 200, 100)
    .frameIfNot(modified, 50)
    .clipRoundedRectangleWithStroke(25, .black, lineWidth: 5)
    .rotateIf(modified, 180.degrees)
    .yOffsetIf(modified, 100)
    .hueRotationIf(modified, 360.degrees)
    .opacityIf(modified, 0.5)

In my opinion, the latter version is significantly more declarative and therefore readable.

Conditional Rendering

SwiftUI of course allow you to render components using conditional logic, and that's fine. Nevertheless this also involves the use of a Group that isn't relevant to the purpose since we are forced to adhere to the opaque return type of body:

@State private var toggle = false


// native SwiftUI
var body: some View {
    Group {
        if toggle {
            Text("It's true")
        } else {

The Group is not part of the design, but it has to be there - assuming we're not type-erasing our components. RenderIf on the other hand is a View, so we can simply return it directly achieving the same result, like so:

@State private var toggle = false


// using RenderIf
var body: some View {
    RenderIf(toggle) {
        Text("It's true")
    }.elseRender {

Furthermore, since RenderIf is a View, modifiers can be applied directly to it and will affect whichever View is ultimately resolved. RenderIf can be used without the else clause if required, however at this point there is no support for else if clauses.

SF Symbols

While SF symbols are a fantastic addition to the framework, none of us likes a stringly typed API, amirite? The process of finding the appropriate symbol using the SF Symbols app and copying the appropriate string into your code is laborious, error-prone, and does not of course provide any type checking. There is also no way - just from looking at the code - of knowing which symbols are restricted in their usage without referring back to the SF Symbols app, or checking out the SF Symbols Reference guide.

Is the following symbol name correct, or restricted in any way?

Image(systemName: "pencil.circle")

Maybe; I'd have to check the documentation. Whereas with PureSwiftUI the first question is moot, and the answer to the second question is clear:


// or using an Image directly
Image(sfSymbol: .pencil_circle)
Image(sfSymbol: .🍏pencil_tip)

Since all SF symbols are available as constants, there is also the option of using fuzzy searching to find a symbol you like the look of in the preview without the need to leave Xcode.

Yet another advantage, is that the symbol constants defined in PureSwiftUI are aware of deprecation so if a symbol you're using has been superseded by a new symbol name, you will get a warning including a suggestion of what to use instead, assuming one exists.

Layout Guides and Paths

PureSwiftUI includes a multitude of extensions and utilities for making drawing paths a breeze, so much so that there are dedicated documents for this topic. See the guide on paths for a detailed explanation of the various available extensions to facilitate drawing, and the section on layout guides which take the process of shape building to the next level.

It is my hope that the ease with which you can construct complex shapes using PureSwiftUI's layout guides and Path extension framework will encourage people to explore their artistic capabilities with constructing paths rather than be turned off by the ubiquitous point calculation logic that appears in most path building example code. Without these hurdles, you really are only limited by you imagination.

Preview Extensions

As with SF Symbols, this is once again a stringly typed interface that PureSwiftUI does away with. Rather than guessing which device strings are accepted, you can pass in a constant to the previewDevice modifier like so:


This has the added benefit of naming the previews based on the device specified, unless you want to override it with your own name of course.

You can also conditionally (or not) set dark mode for a preview device without the need to use the \.colorScheme keypath by using the following:


// or conditionally
MyView.envDarkModeIf(condition) // or envDarkModeIfNot


Although PureSwiftUI exports SwiftUI - meaning you don't need to import SwiftUI at the top of your views for compilation - unfortunately at the time of writing previews do not work if you are not explicitly importing SwiftUI. Hopefully this will be addressed in a future release.


The pure-swift-ui package can be found at:


Instructions for installing swift packages can be found here.


This project adheres to a semantic versioning paradigm. I'm sure a lot will change after WW20, so that's probably when version 2.0.0+ will appear.

Version History

  • 1.0.0 Commit initial code
  • 1.1.0 Update SFSymbols to latest version (1.1 (16))
  • 1.2.0 Add constants for preview device names and add support for SFSymbolName to UIImage
  • 1.3.0 Add deprecated SFSymbols with availability
  • 1.4.0 Add alignment to greedy modifiers and Image specific modifiers to SFSymbol
  • 1.5.0 Add numerous modifiers and conditional modifiers including hueRotation, GeometryProxy extensions, Shape specific modifiers, UIScreen and more
  • 1.6.0 Add image processing modifiers and associated conditionals - add convenience modifiers to Image and SFSymbol to perform resizing and aspect ratio modifiers in one step
  • 1.7.0 Add constructor function for SFSymbols and all font types. Alignment parameter for all frame modifiers. Overloads for all font type modifiers on Text. Conditional animation modifier. Align modifier for Text.
  • 1.8.0 Add various clip shape modifiers - extensions for stroking with fill - fill styles - default corner style to circular for RoundedRectangle - conditional background modifiers
  • 1.9.0 Add conditionals for overlays and borders - add iPhone 11 preview devices - add shadow modifier overloads
  • 1.10.0 Add Frame concept, color name overloads, env and preview modifiers for convenience
  • 1.11.0 Add geometryFrame modifier as well as relativeOffset and offsetToPosition modifiers
  • 1.12.0 Add font modifiers for all font styles to Text and View as well as associated constructor functions
  • 1.13.0 Add a multitude of extensions to types related to drawing paths as well as layout guides to facilitate easy Path construction
  • 1.13.1 Add extension to CGPoint to allow transition to other points by a scale factor for animating paths. Add CG versions of colors to Color.
  • 1.13.2 Internalized LayoutGuide constructor and LayoutCoordinator protocol until the internal API finalizes
  • 1.14.0 Add transforms to layout guides for scaling, rotating and offsetting. Add factors to various scaling functions on convenience extensions to support animatable data in shapes.
  • 1.14.1 Add convenience constructors for CGPoint and LinearGradient and standardize various API calls.
  • 1.14.2 Add static constructor for CGPoint and convenience constructor for LinearGradient specifying angle with further standardization of API.
  • 1.15.0 Fix for segmentation fault in Xcode 11.4 and Cocoapods support
  • 1.15.1 Fix for build failure in XCode 11.5-beta-01


This project is licensed under the MIT License - see here for details.


You can contact me on Twitter @CodeSlice. Happy to hear suggestions for improving the package, or feature suggestions. I've probably made a few boo boos along the way, so I'm open to course correction. I won't be open-sourcing the project for the moment since I simply don't have time to administer PRs at this point, though I do intend to do so in the future if there's enough interest.


Stars: 298