How to Add SwiftUI Views, Navigation, and State in Swift Playgrounds

Go beyond a single screen: a practical guide to composing SwiftUI views, managing state, and adding navigation in Swift Playgrounds on iPad or Mac.

From One Screen to a Real App

A first SwiftUI app is usually a single screen. Real apps have multiple views, shared state, and navigation between screens.

This guide shows how to grow your Swift Playgrounds project from one view into a small, structured app.

The concepts here, view composition, state, and navigation, are the backbone of nearly every iOS app you will ever build.

Everything uses genuine SwiftUI, so the patterns carry straight into Xcode and professional projects.

Step 1: Split Your UI Into Multiple Views

Start by breaking a large body into smaller views. In SwiftUI, a view is a struct that conforms to View and returns a body.

Create a new struct for a logical chunk of your UI, such as a row, a card, or a header.

Then use that view by name inside your main view's body, the same way you use built-in views like Text or Image.

Smaller views are easier to read, reuse, and test. This single habit keeps your code maintainable as the app grows.

Step 2: Pass Data Into Views

Child views usually need data from their parent. You supply it through properties on the child struct.

Declare a constant property on the child view, then pass a value when you create it in the parent.

For example, a row view might take a title string and a count integer, and the parent passes specific values for each row.

This one-directional flow, parent gives data to child, keeps your app predictable. Data flows down, and the UI reflects it.

Step 3: Manage Local State With @State

When a view owns data that changes over time, use the @State property wrapper.

Mark a private property with @State, and SwiftUI watches it. When you change the value, the view re-renders automatically.

Use @State for things like a toggle, a text field's contents, or a counter that belongs to one screen.

Keep @State private and local. It is meant for state a single view owns, not for sharing across many screens.

Step 4: Share State With Bindings

Sometimes a child view needs to change data that the parent owns. That is what a binding is for.

Declare the property in the child with the @Binding wrapper, and pass the parent's @State value using the dollar-sign prefix to create the binding.

Now the child can read and write that value, and the parent sees the changes. A classic case is a toggle in a child view controlling a parent's state.

Bindings give you two-way connections without duplicating data. The single source of truth stays in one place.

Step 5: Add Navigation Between Screens

To move between screens, wrap your content in a navigation container. Modern SwiftUI uses NavigationStack for this.

Place your root view inside a NavigationStack, then use NavigationLink to push to a destination view when the user taps.

A NavigationLink takes a label, what the user taps, and a destination, the view to show next.

This gives you the familiar drill-down navigation seen across iOS apps, with the system handling the back button and transitions for you.

Step 6: Display Collections With Lists

Most apps show collections of data, and List is the SwiftUI tool for that.

Feed a List an array of items and a way to identify each one, often by conforming your model to Identifiable.

Inside the List, build a row view for each item, reusing the small views you created earlier.

Combine List with NavigationLink and you get the staple pattern of iOS: a scrollable list where tapping a row pushes a detail screen.

Why View Composition Matters

Before diving into more steps, it is worth understanding why breaking your UI into small views pays off so much.

Large bodies become hard to read quickly. When a single view tries to describe an entire screen, finding and changing one piece means scrolling through everything else.

Small views are reusable. A row or card you define once can appear in many places, and a fix in one spot fixes it everywhere it is used.

They are also easier to reason about in isolation. You can think about one small view's inputs and output without holding the whole screen in your head. This is the same discipline professionals apply in large Xcode projects, just at a friendlier scale.

Step 7: Lay Out Views With Stacks and Modifiers

Composition is not only about separate views; it is also about arranging them on screen.

SwiftUI gives you stacks for layout: VStack arranges children vertically, HStack horizontally, and ZStack layers them front to back. Nesting these covers most layouts you will need early on.

Modifiers adjust how a view looks and behaves. You attach them to a view to set padding, foreground color, font, frame, and more, and they chain one after another.

The key mental model is that each modifier returns a new, modified view. Order can matter, so if a result looks off, try reordering the modifiers and run again to see the difference.

Step 8: Add Interactivity and Respond to Input

An app comes alive when it responds to the user, and SwiftUI makes wiring that up straightforward.

Controls like Button, Toggle, TextField, and Slider connect to your state. A Button runs an action closure when tapped, while a Toggle or TextField binds directly to a value.

For a text field, pass a binding to a @State string, and the field keeps that value in sync as the user types. For a toggle, bind it to a @State boolean.

Because these controls read and write your state, the rest of your UI updates automatically when the user interacts. You describe the relationship once, and SwiftUI keeps everything consistent.

Choosing the Right State Tool

SwiftUI offers several ways to hold data, and picking the right one keeps your app predictable.

Use @State for simple, private data a single view owns, such as a toggle or a counter that lives on one screen.

Use @Binding when a child view needs to read and write a value that a parent owns, so both share a single source of truth.

When data needs to be shared across many screens or outlive a single view, reach for a dedicated observable model object instead. The guiding question is ownership: decide which part of your app truly owns a piece of data, and let the other parts reference it rather than copying it.

Step 9: Scale State With Observable Models

As state grows beyond a single view, move it into a dedicated model object rather than scattering @State everywhere.

SwiftUI provides observation tools so a shared model can publish changes and many views can react to them.

This separates your data and logic from your UI, which makes the app easier to reason about and to grow.

When you reach this point, you are writing apps the same way professionals do in Xcode. Swift Playgrounds got you there, and the project moves to Xcode cleanly when you need its heavier tooling.

Frequently Asked Questions

What's the difference between @State and @Binding?

@State declares data a view owns. @Binding lets a child view read and write a value owned by a parent, creating a two-way connection to a single source of truth.

How do I navigate between screens in SwiftUI?

Wrap your content in a NavigationStack and use NavigationLink to push to a destination view when the user taps a label.

How do I show a list of items?

Use SwiftUI's List with an array of data. Conform your model to Identifiable so each row is uniquely identified, then build a row view for each item.

When should I stop using @State for everything?

Once state is shared across multiple screens, move it into a dedicated observable model object instead of scattering @State across views.

Do these SwiftUI patterns work the same in Xcode?

Yes. Swift Playgrounds uses genuine SwiftUI, so views, state, bindings, and navigation behave identically when you open the project in Xcode.