--- source: ~/DuckDuckGo/apple-browsers.git/main/.cursor/rules/swiftui-style.mdc confidence: 0.9 namespace: work last_synced: 2026-04-28 alwaysApply: false --- # SwiftUI Style Guide with Design System Integration for DuckDuckGo Browser ## View Structure ### View Organization ```swift struct FeatureView: View { // MARK: - Environment and State @Environment(\.colorScheme) var colorScheme @EnvironmentObject var appSettings: AppSettings // MARK: - State and Binding @State private var localState = false @Binding var externalState: Bool // MARK: - View Model @StateObject private var viewModel: FeatureViewModel // MARK: - Body var body: some View { content .onAppear { viewModel.onAppear() } } // MARK: - Subviews @ViewBuilder private var content: some View { // Main content here } } ``` ## Design System Integration ### REQUIRED: Use DesignResourcesKit Colors ALWAYS use semantic colors from DesignResourcesKit instead of hardcoded or system colors: ```swift // ✅ CORRECT - DesignResourcesKit semantic colors Text("Title") .foregroundColor(Color(designSystemColor: .textPrimary)) .background(Color(designSystemColor: .surface)) VStack { Rectangle() .fill(Color(designSystemColor: .accent)) Button("Action") { } .foregroundColor(Color(designSystemColor: .controlsFillPrimary)) } .background(Color(designSystemColor: .background)) // ❌ INCORRECT - Hardcoded or system colors Text("Title") .foregroundColor(.black) // Don't use hardcoded colors .background(.gray) // Don't use system colors // ❌ INCORRECT - Manual dark mode handling @Environment(\.colorScheme) var colorScheme let textColor = colorScheme == .dark ? Color.white : Color.black // Use semantic colors instead ``` ### REQUIRED: Use DesignResourcesKit Icons ALWAYS use icons from DesignResourcesKitIcons package: ```swift // ✅ CORRECT - DesignResourcesKit icons Button(action: addAction) { Image(uiImage: DesignSystemImages.Glyphs.Size16.add) .foregroundColor(Color(designSystemColor: .accent)) } Image(uiImage: DesignSystemImages.Color.Size24.bookmark) .resizable() .frame(width: 24, height: 24) // ❌ INCORRECT - System or custom icons Button(action: addAction) { Image(systemName: "plus") // Use DesignResourcesKit icons } Image("custom_icon") // Use DesignResourcesKit icons instead ``` ### Design System Color Categories Use appropriate semantic color categories: ```swift // Text colors .foregroundColor(Color(designSystemColor: .textPrimary)) .foregroundColor(Color(designSystemColor: .textSecondary)) .foregroundColor(Color(designSystemColor: .textLink)) // Background colors .background(Color(designSystemColor: .background)) .background(Color(designSystemColor: .surface)) .background(Color(designSystemColor: .panel)) // Control colors .foregroundColor(Color(designSystemColor: .controlsFillPrimary)) .foregroundColor(Color(designSystemColor: .controlsFillSecondary)) // Button colors (use specific button color tokens) .foregroundColor(Color(designSystemColor: .buttonPrimaryText)) .background(Color(designSystemColor: .buttonPrimaryBackground)) ``` ### Typography with Design System Use semantic typography that integrates with the design system: ```swift // ✅ CORRECT - Design system typography Text("Header") .font(.title2.weight(.semibold)) .foregroundColor(Color(designSystemColor: .textPrimary)) Text("Body") .font(.body) .foregroundColor(Color(designSystemColor: .textSecondary)) Text("Caption") .font(.caption) .foregroundColor(Color(designSystemColor: .textSecondary)) // Platform-specific typography (macOS) #if os(macOS) Text("Preference Title") .font(Fonts.preferencePaneTitle) .foregroundColor(Color(designSystemColor: .textPrimary)) #endif ``` ### Theme Integration Use Theme protocol for complex scenarios: ```swift // ✅ CORRECT - Theme integration for advanced scenarios struct ComplexView: View { @EnvironmentObject var themeManager: ThemeManager var body: some View { VStack { Text("Content") .foregroundColor(Color(themeManager.currentTheme.textColor)) } .background(Color(themeManager.currentTheme.backgroundColor)) } } // ✅ PREFERRED - Direct semantic colors for simple cases struct SimpleView: View { var body: some View { Text("Content") .foregroundColor(Color(designSystemColor: .textPrimary)) .background(Color(designSystemColor: .background)) } } ``` ## Component Patterns ### Reusable Components - Create small, focused components - Use ViewModifiers for common styling - Leverage ViewBuilder for conditional content ```swift struct PrimaryButton: View { let title: String let action: () -> Void var body: some View { Button(action: action) { Text(title) .foregroundColor(.white) .padding() .background(Color.accentColor) .cornerRadius(8) } } } ``` ### Lists and Navigation ```swift List { Section { ForEach(items) { item in NavigationLink(destination: DetailView(item: item)) { ItemRow(item: item) } } } header: { Text("Section Title") } } .listStyle(.insetGrouped) ``` ## State Management ### View Model Pattern ```swift class FeatureViewModel: ObservableObject { @Published var items: [Item] = [] @Published var isLoading = false @Published var error: Error? func loadData() async { isLoading = true defer { isLoading = false } do { items = try await service.fetchItems() } catch { self.error = error } } } ``` ### Async Operations ```swift struct ContentView: View { @StateObject private var viewModel = ViewModel() var body: some View { content .task { await viewModel.loadData() } .refreshable { await viewModel.refresh() } } } ``` ## Animations and Transitions ### Smooth Animations ```swift @State private var isExpanded = false var body: some View { VStack { content .frame(height: isExpanded ? 200 : 100) .animation(.spring(), value: isExpanded) } } ``` ### Custom Transitions ```swift .transition(.asymmetric( insertion: .move(edge: .trailing).combined(with: .opacity), removal: .move(edge: .leading).combined(with: .opacity) )) ``` ## Accessibility ### Always Include Accessibility ```swift Image(systemName: "star.fill") .accessibilityLabel("Favorite") .accessibilityHint("Double tap to toggle favorite status") Button(action: action) { Text("Submit") } .accessibilityIdentifier("submit_button") ``` ## Performance Considerations ### Lazy Loading ```swift ScrollView { LazyVStack { ForEach(items) { item in ItemView(item: item) } } } ``` ### Avoid Expensive Operations in Body ```swift // Bad var body: some View { let processedData = expensiveOperation(data) // Don't do this Text(processedData) } // Good @State private var processedData: String = "" var body: some View { Text(processedData) .onAppear { processedData = expensiveOperation(data) } } ``` ## Preview Support ### Comprehensive Previews ```swift struct FeatureView_Previews: PreviewProvider { static var previews: some View { Group { FeatureView() .previewDisplayName("Default") FeatureView() .preferredColorScheme(.dark) .previewDisplayName("Dark Mode") FeatureView() .previewDevice("iPhone SE (3rd generation)") .previewDisplayName("Small Device") } } } ```