List Alternative

Status: ready

Intent

Spatial UI (a map, a chart, a canvas) has a list path for the same task.

Problem

The data exists, but the app shows it only as positions, pins or shapes. Comparing and choosing requires panning, pinching and tapping exact points.

Solution

Verdict: the same data as a list, with the fields that matter for the decision and a selection action in each row. Map and list share one filtered, sorted source.

Why: a list works with every input method and can be read at any text size. Sharing the source keeps both views telling the same story.

The Map and List selector is set to List, showing two pickup points with independent selection actions.
List alternative: two pickup points appear as labeled rows with separate selection buttons. Captured on iPhone 17 Pro Max, iOS 27.0.1.

Implementation

One source for both views:

var visiblePoints: [PickupPoint] {
    points
        .filter { $0.matches(activeFilters) }
        .sorted { $0.distance < $1.distance }
}

A row has the data needed to compare, and the selection as a trait:

List(visiblePoints) { point in
    VStack(alignment: .leading) {
        Text(point.name).font(.headline)
        Text("\(point.distanceText) · \(point.hoursText)")
        Button("Pick up here") { selected = point }
            .accessibilityLabel("Pick up at \(point.name)")
            .accessibilityInputLabels(["Pick up here", "Pick up at \(point.name)"])
            .accessibilityAddTraits(selected == point ? .isSelected : [])
    }
}

The map can stay as a preview above the list. Map for orientation, list for a reliable choice.

The same applies to charts: if the user needs the numbers, give them the numbers.

List(spending) { category in
    Text("\(category.name): \(category.amount), \(category.percent)%")
}

For Swift Charts, .accessibilityChartDescriptor adds an Audio Graph and a data table to the chart itself. Chapter 11 covers AXChart for UIKit.

Check

Profile:   VoiceOver
Task:      choose the nearest open pickup point
Expected:  done from the list
           each row reads name, distance, hours
           the selected row says "Selected"
Profile:   Switch Control
Task:      the same
Expected:  rows, filters and sort are scan targets, no pan or pinch
Profile:   Larger Text AX3
Task:      compare rows
Expected:  row text wraps, distance stays with its point

Pitfalls

  1. Filters that apply to the map and not the list.
  2. A read-only list when the map can select.
  3. Different names for the same point on the map and in the list.
  4. Distance or hours only in the pin callout.
  5. Two points with the same name and no address to tell them apart.

WCAG mapping

  1. 1.3.1 Info and Relationships: data relationships are programmatic.
  2. 1.4.1 Use of Color: selection isn't only color.
  3. 2.5.1 Pointer Gestures: spatial gestures have alternatives.
  1. Map Dead End
  1. Chapter 7
  2. Chapter 10
  3. Chapter 17

Sources

  1. Apple Human Interface Guidelines: Maps
  2. Apple Developer: MapKit for SwiftUI
  3. Apple Developer: AXChart