WWDC Quick Look 💓 By SwiftGGTeam
Principles of great design

Principles of great design

Watch original video

Highlight

Apple defines design as “creation with intention.” Around eight principles — Purpose, Agency, Responsibility, Familiarity, Flexibility, Simplicity, Craft, and Delight — it gives developers a design guide that is especially important in the AI era: every feature consumes users’ time, attention, and trust, and deciding what not to build matters more than deciding what to build.

Core Content

Purpose: Think Clearly Before You Start

(00:32)

When many teams receive a requirement, their first instinct is to draw a prototype or write code. Apple begins this session with a cold shower: before drawing the first line or writing the first line of code, ask yourself whether this thing has Purpose.

Every feature you add to a product asks users for time, attention, and trust. Those are expensive resources, and you cannot afford to waste them. So deciding “what not to do” often tests your judgment more than deciding “what to do.” If a feature exists, it needs a clear value proposition, not just “others have it, so we need it too.”

Agency: Give Control Back to Users

(01:52)

Agency is about letting users do things their own way. The interface should not stand between users and their goals, and it should not force them down one predetermined path.

But when users have freedom, they make mistakes. That is where Forgiveness needs to catch them. If a user deletes a file by mistake or sends the wrong message, Undo should be easy. Blocking confirmation dialogs should be reserved for truly irreversible destructive actions. This kind of design lets users explore because they know the system has their back.

Responsibility: Privacy and Safety Are the Baseline

(03:38)

Responsibility begins with privacy. Apple’s position is clear: do not throw permission requests at users the moment the app launches. Before users understand what the app does, they are asked to give up location, photos, or contacts. It is like a stranger asking for your phone number immediately; would you trust them?

A responsible interface asks for data at the right moment, asks only for necessary data, and explains its purpose transparently.

The AI context deserves even more attention. (05:10) Apple gives the example of a recipe app: if a user has marked a peanut allergy and the AI recommends a recipe containing peanuts, that can cause real physical harm. Apple’s stance is to anticipate the worst case and add safety guardrails. If the risk outweighs the value, remove the feature outright instead of pushing the problem onto users with an “AI may be inaccurate” disclaimer.

Familiarity: Use What Users Already Know

(06:02)

Familiarity means using what users already know instead of copying other designs blindly. Metaphors have been part of graphical interfaces from the beginning: a trash can means delete because users know a real trash can holds things they no longer want.

Good metaphors should not be too concrete, because users may not have seen the original object, or too abstract, because users may not guess the function. Consistency is also critical: controls that look the same must behave the same way; common actions should stay in fixed locations across screens and devices. The close button on the Mac is always in the upper-left corner, so users know where to click without thinking.

Flexibility: Adapt to Different Contexts of Use

(08:54)

The same person interacts with music very differently at home, while running, and while driving. Flexible interfaces adapt to these real contexts: quick touch interactions on iPhone, deeper workflows on Mac, and fully hands-free behavior in CarPlay.

Flexibility also means inclusivity. Users differ in age, language, and ability. You do not need to cover everyone on day one, but you should begin thinking about how to make the experience more inclusive. For example, let users customize control layouts or hide buttons they rarely use.

Simplicity: Remove the Unnecessary So the Core Purpose Can Shine

(11:13)

Apple deliberately distinguishes Simplicity from Minimalism. If you put every feature into one menu, the interface may look clean, but it becomes harder to use. Real simplicity removes friction: users can find what they need with no effort.

Simplicity comes from being Concise and Clear. A concise interface uses plain language, removes jargon, and reduces steps. A clear interface uses hierarchy to guide attention; order, spacing, and contrast make the most important thing on the screen visible at a glance.

Sometimes simplicity actually means adding content. (13:06) A simple play/pause button is not enough when users return after pausing for a while. They need more context: where did playback stop, and how much time is left? Adding that information lets users make informed decisions, and that is simplicity.

Craft: Details Determine Trust

(13:42)

Craft is the care users can feel. A button that does nothing when tapped, stuttering scroll, misaligned icons, or a layout that breaks on rotation all make users question the quality of the entire product.

High-quality craft includes typography that looks good across devices, colors that adapt to light and dark modes, clear icons, and smooth animated feedback. These are not extras; they are the foundation of trust. Craft comes from repeated iteration, and it is an ongoing process. When the platform updates or new hardware appears, actively evaluate whether it can improve your experience.

Delight: The Natural Result of Getting Every Principle Right

(15:48)

Delight is hard to define, but you know it when you experience it. Apple’s reminder is direct: do not try to manufacture delight with confetti and effects. Real delight comes from knowing what emotion you want users to feel — relaxed, confident, excited — and reinforcing that emotion consistently in the design. Delight is the natural result of getting all the other principles right.

Details

Replace Blocking Confirmation Dialogs with Undo

In the Agency principle, Forgiveness becomes concrete through strong Undo support. Here is a SwiftUI implementation that combines UndoManager with a bottom toast:

struct TaskListView: View {
    @State private var tasks = ["Write weekly report", "Review code", "Update documentation"]
    @Environment(\.undoManager) private var undoManager
    @State private var showUndoToast = false
    @State private var deletedTask: String?
    @State private var deletedIndex: Int?

    var body: some View {
        List {
            ForEach(tasks, id: \.self) { task in
                Text(task)
            }
            .onDelete { indexSet in
                let index = indexSet.first!
                deletedTask = tasks[index]
                deletedIndex = index
                tasks.remove(at: index)

                undoManager?.registerUndo(withTarget: self) { target in
                    if let task = target.deletedTask,
                       let idx = target.deletedIndex {
                        target.tasks.insert(task, at: idx)
                    }
                }
                undoManager?.setActionName("Delete task")
                showUndoToast = true

                DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                    showUndoToast = false
                }
            }
        }
        .overlay(alignment: .bottom) {
            if showUndoToast {
                HStack(spacing: 12) {
                    Text("Deleted")
                    Button("Undo") {
                        undoManager?.undo()
                        showUndoToast = false
                    }
                    .fontWeight(.semibold)
                }
                .padding(.horizontal, 16)
                .padding(.vertical, 10)
                .background(.ultraThinMaterial, in: Capsule())
                .padding(.bottom, 40)
            }
        }
    }
}

Key points:

  • @Environment(\.undoManager) gets the system undo manager, including system gestures such as Shake to Undo
  • registerUndo(withTarget:) registers the inverse operation and inserts the deleted data back into its original position
  • setActionName(_:) sets the undo action’s display name, visible in the system undo menu
  • A non-blocking bottom toast replaces an Alert, so users can continue operating and the toast disappears after three seconds
  • Blocking confirmation should be used only for truly irreversible operations, such as clearing a database or closing an account

Responsible Permission Requests: Just-in-Time Strategy

The Responsibility principle requires permission requests to happen at the right moment. SwiftUI’s PhotosPicker naturally follows this principle:

struct ProfileSetupView: View {
    @State private var selectedItems: [PhotosPickerItem] = []
    @State private var showPicker = false

    var body: some View {
        VStack(spacing: 20) {
            Text("Set profile photo")
                .font(.title2)

            Button("Choose from Photos") {
                showPicker = true
            }
            .buttonStyle(.borderedProminent)
        }
        .photosPicker(
            isPresented: $showPicker,
            selection: $selectedItems,
            matching: .images
        )
        .onChange(of: selectedItems) { _, newItems in
            guard let item = newItems.first else { return }
            loadImage(from: item)
        }
    }

    private func loadImage(from item: PhotosPickerItem) {
        item.loadTransferable(type: Data.self) { result in
            // Process the selected image data
        }
    }
}

Key points:

  • The permission dialog appears only when the user taps “Choose from Photos,” not when the app launches
  • PhotosPicker requests Limited Access by default, meaning only selected photos, which follows the principle of least privilege
  • Avoid using the older UIImagePickerController to request Full Access, which carries a higher review risk
  • After selection, load data asynchronously through loadTransferable so the main thread is not blocked

Use Haptic Feedback to Strengthen Craft

The Craft principle calls for precise interface feedback. SwiftUI’s sensoryFeedback makes haptic feedback declarative:

struct CheckInButton: View {
    @State private var isCheckedIn = false

    var body: some View {
        Button {
            isCheckedIn.toggle()
        } label: {
            Image(systemName: isCheckedIn ? "checkmark.circle.fill" : "circle")
                .font(.system(size: 56))
                .foregroundStyle(isCheckedIn ? .green : .gray)
                .contentTransition(.symbolEffect(.replace))
        }
        .sensoryFeedback(.success, trigger: isCheckedIn) { oldValue, newValue in
            newValue == true
        }
        .sensoryFeedback(.impact, trigger: isCheckedIn) { oldValue, newValue in
            newValue == false
        }
    }
}

Key points:

  • .sensoryFeedback(_:trigger:condition:) is available in iOS 17 and later, and the condition closure controls when it fires
  • A successful check-in uses .success, while cancelling uses .impact, clearly distinguishing state changes
  • Do not call UIImpactFeedbackGenerator directly inside body, because that breaks the declarative structure
  • Pair it with .contentTransition(.symbolEffect(.replace)) so icon transition animation and haptics stay in sync

Key Takeaways

What to do: Add a “worst case” checklist to AI features Why it is worth doing: The session explicitly asks developers to anticipate risks in AI output. A recipe app that recommends the wrong ingredient to someone with an allergy can endanger physical safety. That is not a UX issue; it is a responsibility issue. How to start: For every AI feature, list three questions: What happens if this feature is misused? Who could be harmed? How can we prevent it? If the risk is hard to control, add a second confirmation or human review. If the risk outweighs the value, remove the feature.

What to do: Move all launch-time permission requests to business-triggered moments Why it is worth doing: The Responsibility principle emphasizes “asking at the right moment.” Showing permissions at launch is a major cause of user drop-off. How to start: Scan AppDelegate, App initialization code, and all requestAuthorization calls. Move permission requests into code paths where users actively trigger the relevant feature. Use PhotosPicker instead of manually requesting photo library permission, and call CoreLocation’s requestWhenInUseAuthorization only when entering map-related screens.

What to do: Replace 80% of confirmation dialogs with Undo Why it is worth doing: The core of Agency is letting users explore with confidence. Every Alert asking “Are you sure you want to delete this?” consumes patience and trust. How to start: Audit all uses of UIAlertController and confirmationDialog. For recoverable operations, such as deleting list items, removing tags, or unfavoriting content, use UndoManager plus a bottom toast. Keep confirmation dialogs only for truly irreversible operations, such as clearing a database, closing an account, or transferring money.

What to do: Add haptic feedback to key operations Why it is worth doing: The Craft principle asks for “smooth animations that provide immediate, natural feedback.” Haptics are the most direct way to create a sense of physicality. How to start: Add .sensoryFeedback(.success, trigger: state) to key interactions such as submitting forms, completing check-ins, sending messages, and toggling switches. Distinguish success and failure feedback types, such as .success versus .error, so users can perceive the result through touch alone.

What to do: Run a “consistency audit” Why it is worth doing: The Familiarity principle says that “things that look the same must behave the same.” Inconsistent interfaces confuse users and increase learning cost. How to start: List every button, card, and list item behavior in the app. Check whether controls with the same visual style share the same behavior. For example, every strikethrough button should mean delete, and every three-dot menu in the upper-right should mean more options. Standardize the inconsistent cases.

  • Principles of great design — Design principles for brand identity and visual systems, aligned with the design philosophy of this session
  • SwiftUI essentials — New SwiftUI features that support the Agency and Simplicity principles from Session 250
  • UIKit modernization — UIKit modernization improvements that help existing codebases apply the Craft and Familiarity principles
  • Accessibility Reading — Accessible reading experiences that map to the inclusive design side of the Flexibility principle
  • Agentic apps — AI agent app design, where the Responsibility principle is especially important for feature safety

Comments

GitHub Issues · utterances