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.