# Content views in detail

Companion to `../SKILL.md` for the `hig-components-content` skill.

## Lists and tables

- Rows should read left to right as: leading image or symbol, primary text,
  secondary text, trailing value or accessory. Keep that order stable across
  every row in a list so the eye can run down one column.
- Swipe actions are shortcuts, not the only path. Anything in
  `.swipeActions` must also be reachable from a context menu or the detail
  screen, because swipes are undiscoverable and awkward with VoiceOver.
- Destructive swipe actions use `role: .destructive`, and a full swipe should
  only trigger an action that can be undone or that asks first.
- Use `.contextMenu` for secondary actions on a row, with a preview when the
  row opens into something visual.
- Selection: `List(selection:)` gives the system edit mode, multi-select with
  two-finger pan on iPad, and keyboard selection on Mac. Do not build custom
  checkmark rows for this.
- `.refreshable` gives the standard pull-to-refresh; do not add a manual
  refresh button to the same list on iOS.
- Section headers are for grouping, not decoration. If every section has one
  row, the grouping is probably wrong.

```swift
List(selection: $selectedOrderIDs) {
    ForEach(orders) { order in
        OrderRow(order: order)
            .swipeActions(edge: .trailing) {
                Button("Archive", systemImage: "archivebox") { archive(order) }
                    .tint(.indigo)
            }
            .contextMenu {
                Button("Archive", systemImage: "archivebox") { archive(order) }
                ShareLink(item: order.receiptURL)
            }
    }
}
.refreshable { await store.reload() }
```

## Collections and grids

- Prefer adaptive columns (`GridItem(.adaptive(minimum: 140))`) so the grid
  reflows from iPhone portrait to a Mac window without per-device code.
- Keep item spacing consistent and let the content define the item, not a
  heavy card border. On iOS 26, avoid stacking glass effects on grid items;
  glass belongs to controls and navigation layered above content.
- Large data sets need the lazy stacks and grids; `Grid` lays out every child
  eagerly and suits a dozen cells, not a thousand.
- Give tappable cells a clear pressed state and a context menu, the same as
  list rows.

## Charts

- A chart must answer one question at a glance. Title it with the question or
  the conclusion ("Orders per week, last quarter"), not the data source.
- Choose the mark from the comparison: bars for discrete categories, lines for
  change over continuous time, sectors only for a few parts of one whole.
- Colour is never the only carrier of meaning. Add `.foregroundStyle(by:)`
  with a legend and a second cue (symbol shape, direct labels, pattern).
- Provide `.accessibilityLabel` and `.accessibilityValue` on marks, or an
  audio graph via `AXChartDescriptorRepresentable`, so VoiceOver users get
  the same answer.
- Use `.chartXSelection` / `.chartScrollableAxes` for exploration instead of
  bespoke gesture code.
- Small inline charts (sparklines in a row or widget) drop axes and legends
  entirely and must still make sense without them.

## Images and media

- Supply images at the scales the device needs, or use SF Symbols and vector
  assets so they scale with Dynamic Type and the display.
- Every meaningful image gets an accessibility label; decorative ones get
  `.accessibilityHidden(true)` or `Image(decorative:)`.
- `AsyncImage` needs a placeholder with the final aspect ratio so layout does
  not jump when the image arrives.
- Let people zoom and pan full-screen images with the standard gestures; a
  double tap toggles between fit and a closer zoom.
- For video use `VideoPlayer` or `AVPlayerViewController` so people get
  system controls, Picture in Picture and AirPlay for free.

## Text

- Use text styles (`.body`, `.headline`, `.caption`) so Dynamic Type works;
  never fix a point size for reading text.
- Make read-only text selectable with `.textSelection(.enabled)` when people
  might want to copy it (an order number, a tracking code, an address).
- Long editable text belongs in `TextEditor` or a multi-line `TextField`, not
  a single-line field that scrolls sideways.

## Web content

- Use an embedded web view only for content that is part of the app's own
  experience (help pages, rendered documents). For arbitrary external links,
  hand off to Safari or `SFSafariViewController` so people keep their
  cookies, autofill and content blockers.
- On iOS 26, the SwiftUI `WebView` with a `WebPage` model replaces most
  `UIViewRepresentable` wrappers around `WKWebView`.
- Do not rebuild a browser: no custom address bar, no custom back stack
  unless the web content is the whole product.

## Sharing

- `ShareLink` presents the system share sheet; make the shared item a
  `Transferable` type so it exports the richest representation available
  and falls back gracefully (a file, then a URL, then plain text).
- Put the share action where the object is shown (toolbar of the detail view,
  context menu of the row), and use the standard `square.and.arrow.up` symbol.
- Provide a `SharePreview` with a title and image so the sheet shows what is
  being sent.
