Lists, ForEach & Navigation
Most apps show lists of data and let you tap a row to see details. You'll build scrollable lists with List , generate rows from data with ForEach and Identifiable , and wire up screen-to-screen navigation with NavigationStack and NavigationLink .
Learn Lists, ForEach & Navigation in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Building iOS Apps with SwiftUI • Intermediate
What You'll Learn in This Lesson
1️⃣ List — Scrollable Rows
List renders a scrollable, platform-styled column of rows, complete with separators. The simplest form just contains a few static views.
2️⃣ ForEach & Identifiable — Rows from Data
Real lists come from data. ForEach builds one row per element. For SwiftUI to track rows correctly, each element needs a stable identity — conform your model to Identifiable by giving it an id .
For plain values like strings that aren't Identifiable , pass an id key path instead.
3️⃣ NavigationStack & NavigationLink
Wrap your content in a NavigationStack to enable pushing detail screens. A NavigationLink shows a row that, when tapped, pushes its destination onto the stack. Add a title with .navigationTitle(...) .
Your turn. Fill in the blanks to build a navigable library list.
Define a Contact: Identifiable struct with a name and phone number. Build a List inside a NavigationStack that uses ForEach to show each contact's name, with a NavigationLink to a detail screen showing the full name and number. Give the list the title "Contacts".
Practice quiz
What does the List view do?
- Draws a single row
- Shows a scrollable column of rows
- Sorts an array
- Stores data
Answer: Shows a scrollable column of rows. List presents data in a scrollable, platform-styled column of rows.
What is ForEach used for in SwiftUI?
- Looping over a collection to build a view per element
- Running a background task
- Repeating an animation
- Filtering data
Answer: Looping over a collection to build a view per element. ForEach creates one view for each element of a collection.
Why must ForEach elements be identifiable?
- For sorting
- So SwiftUI can tell rows apart to update them correctly
- To save memory
- It is optional and never needed
Answer: So SwiftUI can tell rows apart to update them correctly. Stable identity lets SwiftUI track, insert, move, and delete the right rows efficiently.
What does conforming to Identifiable require?
- A name property
- An id property with a stable, unique value
- A description method
- Nothing
Answer: An id property with a stable, unique value. Identifiable requires an id property that uniquely and stably identifies each instance.
How can you give ForEach an id without Identifiable?
- ForEach(items, key: ...)
- ForEach(items, id: \.self) or id: \.someProperty
- ForEach(items).id()
- You cannot
Answer: ForEach(items, id: \.self) or id: \.someProperty. Pass an id key path, e.g. ForEach(items, id: \.self), when the type isn't Identifiable.
What is NavigationStack?
- A list of tabs
- A layout stack
- A container that manages a stack of pushed screens
- An animation
Answer: A container that manages a stack of pushed screens. NavigationStack (iOS 16+) manages a navigation stack, pushing and popping detail screens.
What does NavigationLink do?
- Opens a web URL
- Pushes a destination view when tapped
- Dismisses a sheet
- Reorders a list
Answer: Pushes a destination view when tapped. NavigationLink presents a destination view by pushing it onto the navigation stack when tapped.
Where must a NavigationLink live to work?
- Anywhere at all
- Inside a NavigationStack (or NavigationView)
- Only inside a Button
- Inside a ZStack
Answer: Inside a NavigationStack (or NavigationView). A NavigationLink needs an enclosing NavigationStack to have a stack to push onto.
How do you add a title to a navigation screen?
- .title("X")
- .header("X")
- .name("X")
- .navigationTitle("X")
Answer: .navigationTitle("X"). Apply .navigationTitle("X") to the content inside the NavigationStack to set the bar title.
What is a clean way to combine a List with dynamic rows?
- List with a ForEach over your data
- A ZStack of Texts
- Many nested VStacks
- A single Text
Answer: List with a ForEach over your data. Putting a ForEach inside a List builds one row per element, the standard pattern for dynamic lists.