iOS 27 introduces a new CarPlay video app category allowing users to browse and play videos on supported CarPlay displays, alongside major CarPlay framework enhancements including card thumbnails with overlays, a MiniPlayer for now playing, voice control overlays, and navigation panels.
⢠Video streaming apps can now offer a full browsing UI on CarPlay displays in cars that support the 'video in car' feature, unlocking a new surface for content discovery
⢠The new MiniPlayer for now playing templates is automatically shown for all CarPlay apps, improving the playback experience with zero code changes required
⢠New CPCardElement thumbnails with overlays, playback progress, and sports scores give all CarPlay apps richer list UIs previously impossible with the framework
Shows how to build a CarPlay video browsing list using the new CPCardElement API with thumbnail overlays and playback progress, and how to check session configuration for video support.
import CarPlay
import UIKit
class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
var interfaceController: CPInterfaceController?
func templateApplicationScene(
_ templateApplicationScene: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController
) {
self.interfaceController = interfaceController
let sessionConfig = templateApplicationScene.sessionConfiguration
let supportsVideo = sessionConfig.contentStyle == .video
let rootTemplate = buildRootTemplate(supportsVideo: supportsVideo)
interfaceController.setRootTemplate(rootTemplate, animated: false, completion: nil)
}
func buildRootTemplate(supportsVideo: Bool) -> CPListTemplate {
var sections: [CPListSection] = []
if supportsVideo {
let videoSection = buildVideoSection()
sections.append(videoSection)
}
let audioSection = buildAudioSection()
sections.append(audioSection)
let template = CPListTemplate(title: "Landmarks", sections: sections)
return template
}
func buildVideoSection() -> CPListSection {
// Build a card element with thumbnail overlay and playback progress
let thumbnailImage = UIImage(systemName: "mountain.2.fill") ?? UIImage()
let overlay = CPThumbnailOverlay(title: "New")
let playbackConfig = CPPlaybackConfiguration(
elapsedTime: 120,
duration: 600,
playbackAction: .play
)
playbackConfig.preferredPresentation = .video
let cardElement = CPCardElement(
title: "The Alps",
image: thumbnailImage,
imageAspectRatio: .landscape,
overlay: overlay,
playbackConfiguration: playbackConfig
)
let listItem = CPListItem(cardElement: cardElement)
listItem.handler = { [weak self] item, completion in
self?.pushVideoDetailTemplate()
completion()
}
return CPListSection(items: [listItem], header: "Videos", sectionIndexTitle: nil)
}
func buildAudioSection() -> CPListSection {
let audioItem = CPListItem(text: "Alps Audio Story", detailText: "12 min")
audioItem.handler = { _, completion in
// Begin audio playback
completion()
}
return CPListSection(items: [audioItem], header: "Audio Stories", sectionIndexTitle: nil)
}
func pushVideoDetailTemplate() {
let headerImage = UIImage(systemName: "mountain.2.fill") ?? UIImage()
let playbackConfig = CPPlaybackConfiguration(
elapsedTime: 0,
duration: 600,
playbackAction: .play
)
playbackConfig.preferredPresentation = .video
let playButton = CPTextButton(title: "Play", textStyle: .normal) { _ in
// Trigger AirPlay video playback
}
let detailsHeader = CPDetailsHeader(
title: "The Alps",
subtitle: "Switzerland",
bodyText: "A breathtaking journey through the Swiss Alps.",
image: headerImage,
playbackConfiguration: playbackConfig,
actionButtons: [playButton]
)
let relatedItem = CPListItem(text: "Related: Dolomites", detailText: "8 min")
let section = CPListSection(items: [relatedItem])
let detailTemplate = CPListTemplate(title: "Alps", sections: [section])
detailTemplate.detailsHeader = detailsHeader
interfaceController?.pushTemplate(detailTemplate, animated: true, completion: nil)
}
func templateApplicationScene(
_ templateApplicationScene: CPTemplateApplicationScene,
didDisconnect interfaceController: CPInterfaceController
) {
self.interfaceController = nil
}
}Liquid Glass is Apple's new material and visual design language introduced in iOS 27, bringing translucent, refractive glass-like surfaces to system and custom UI elements. It replaces the frosted vibrancy aesthetic with a more dynamic, depth-aware material that responds to content beneath it.
PaperKit is Apple's full-featured canvas framework ā previously internal-only ā now publicly available in iOS/macOS/visionOS 27. It powers the drawing and markup experience in Notes, Preview, and Freeform, giving developers access to a complete pencil, shapes, images, and text canvas with a rich data model.
Xcode 27 introduces a fully customizable toolbar and theme system, untitled scratch projects, coding agent integration directly in the editor, and the new Device Hub for evaluating apps across simulators and physical devices side-by-side.
In-depth guide
SwiftUI & Liquid Glass in iOS 27 āApps with only the CarPlay video entitlement won't appear on CarPlay home screen in cars that don't support video in car ā include both audio and video entitlements if your content works as audio-only too. At runtime the car may disable video playback and fall back to audio-only; always check CPSessionConfiguration for video support before presenting video UI. Voice Control template overlay requires the interface controller to explicitly present it as an overlay.
CarPlay video app category requires cars that support the 'video in car' feature; MiniPlayer is available on all CarPlay-enabled vehicles but playback controls require a larger display
iOS 27 introduces new SwiftUI drag and drop APIs including reorderable, reorderContainer, dragContainer, and configuration modifiers that enable reordering within and across collections, multi-item drag, and fine-grained control over how data is transferred during drag and drop operations.