Styling & Theming
iOS SDK: Styling & Theming
Customize colors, typography, spacing, and component styles throughout the Digital Card Engine UI SDK using the centralized StyleConfiguration system.
Prerequisites:
- SDK initialized with
DigitalCardEngine - Access to the
sdk.styleConfigurationinstance
StyleConfiguration Overview
The SDK uses a single StyleConfiguration object that controls the visual appearance of all UI components. This matches the Android SDK design for cross-platform consistency.
let sdk = try DigitalCardEngine(/* ... */)
// After initialization, customize appearance
sdk.styleConfiguration.palette.secondary = Color(hex: 0xFF5722)
sdk.styleConfiguration.spacing = 12Palette (Color System)
The Palette defines semantic colors used throughout the SDK. All colors follow Material Design 3 naming conventions and match Android exactly.
public struct Palette {
public var surface: Color = .init(hex: 0xffffff) // Backgrounds
public var onSurface: Color = .init(hex: 0x1C1B1B) // Primary text
public var onSurfaceVariant: Color = .init(hex: 0x5C5F66) // Secondary text
public var primary: Color = .init(hex: 0x0019BF) // Primary brand
public var secondary: Color = .init(hex: 0x2353C8) // Secondary brand/accent
public var success: Color = .init(hex: 0x1A7F37) // Success/positive
public var outlineVariant: Color = .init(hex: 0xE4E6EB) // Borders/dividers
public var surfaceContainerHighest: Color = .init(hex: 0xE0E3E8) // Subtle backgrounds
public var surfaceContainerLow: Color = .init(hex: 0xF3F4F7) // Light backgrounds
}Color Usage Guide
| Color | Default | Usage |
|---|---|---|
surface | #FFFFFF | Card backgrounds, container surfaces |
onSurface | #1C1B1B | Primary text (titles, card labels) |
onSurfaceVariant | #5C5F66 | Secondary text (subtitles, metadata) |
primary | #0019BF | Primary brand elements |
secondary | #2353C8 | Action buttons, brand elements |
success | #1A7F37 | Positive amounts, success indicators |
outlineVariant | #E4E6EB | Dividers, borders, separators |
surfaceContainerHighest | #E0E3E8 | Card backgrounds when stacked |
surfaceContainerLow | #F3F4F7 | Light container backgrounds |
Customizing Colors
// Apply your brand colors
sdk.styleConfiguration.palette = Palette(
surface: Color.white,
onSurface: Color(hex: 0x1A1A1A),
onSurfaceVariant: Color(hex: 0x666666),
primary: Color(hex: 0x0019BF),
secondary: Color(hex: 0x00A86B), // Your brand color
success: Color(hex: 0x1A7F37),
outlineVariant: Color(hex: 0xE0E0E0),
surfaceContainerHighest: Color(hex: 0xF5F5F5),
surfaceContainerLow: Color(hex: 0xF9F9F9)
)Typography (Fonts & TypeScale)
The SDK uses Material Design 3 typography scales. Each scale has a regular and emphasized (bold) variant.
public struct Fonts {
// Title
var titleLarge: TypeScale
var titleMedium: TypeScale
var titleSmall: TypeScale
// Label
var labelLarge: TypeScale
var labelMedium: TypeScale
var labelSmall: TypeScale
// Body
var bodyLarge: TypeScale
var bodyMedium: TypeScale
var bodySmall: TypeScale
}
public struct TypeScale {
let font: Font // Regular weight
let fontEmphasized: Font // Bold/emphasized weight
let tracking: CGFloat // Letter spacing
}Typography Scale Reference
| Scale | Size | Tracking | Usage |
|---|---|---|---|
titleLarge | 22pt | 0pt | Screen titles, large headings |
titleMedium | 16pt | 0.15pt | Section titles, card titles |
titleSmall | 14pt | 0.1pt | Small headings, labels |
labelLarge | 14pt | 0.1pt | Button text, prominent labels |
labelMedium | 12pt | 0.5pt | Input labels, metadata |
labelSmall | 11pt | 0.5pt | Captions, small metadata |
bodyLarge | 16pt | 0.5pt | Primary body text |
bodyMedium | 14pt | 0.25pt | Secondary body text |
bodySmall | 12pt | 0.4pt | Small body text, footnotes |
Default Font Configuration
public struct Fonts {
var titleLarge: TypeScale = .init(
font: .montserratRegular(size: 22),
fontEmphasized: .montserratMedium(size: 22),
tracking: 0
)
var titleMedium: TypeScale = .init(
font: .montserratMedium(size: 16),
fontEmphasized: .montserratBold(size: 16),
tracking: 0.15
)
var bodyMedium: TypeScale = .init(
font: .montserratRegular(size: 14),
fontEmphasized: .montserratMedium(size: 14),
tracking: 0.25
)
// ... other scales
}Custom Typography
import SwiftUI
// Define custom fonts
extension Font {
static func myCustomRegular(size: CGFloat) -> Font {
.custom("MyFont-Regular", size: size)
}
static func myCustomBold(size: CGFloat) -> Font {
.custom("MyFont-Bold", size: size)
}
}
// Apply custom fonts
sdk.styleConfiguration.fonts.bodyMedium = TypeScale(
font: .myCustomRegular(size: 14),
fontEmphasized: .myCustomBold(size: 14),
tracking: 0.25
)
sdk.styleConfiguration.fonts.titleLarge = TypeScale(
font: .myCustomRegular(size: 22),
fontEmphasized: .myCustomBold(size: 22),
tracking: 0
)Component-Specific Properties
CardListViewProperties
Control card list behavior and layout.
public struct CardListViewProperties {
public var title: Bool = true
public var actionButton: Bool = true
public var dividers: Bool = true
public var cardListLayout: CardListViewLayout = .largeLayout
}
public enum CardListViewLayout {
case defaultLayout // Compact rows for dashboards
case largeLayout // Spacious cards (default)
}Usage:
sdk.styleConfiguration.cardListViewProperties = CardListViewProperties(
title: false,
actionButton: true,
dividers: true,
cardListLayout: .defaultLayout
)CardDetailsViewProperties
Control card details screen behavior.
public struct CardDetailsViewProperties {
public var actionButton: Bool = true
public var slider: Bool = false
public var cardInfoLayout: CardDetailsViewLayout = .detailLayout
}
public enum CardDetailsViewLayout {
case briefLayout // Compact info
case detailLayout // Full details (default)
}Usage:
sdk.styleConfiguration.cardDetailsViewProperties = CardDetailsViewProperties(
actionButton: true,
slider: true,
cardInfoLayout: .detailLayout
)TransactionHistoryViewProperties
Control transaction history display.
public struct TransactionHistoryViewProperties {
public var leadingElement: TransactionHistoryLeadingElement = .icon
public var groupByMonth: Bool = true
public var timestampFormat: String = "dd/MM/yyyy HH:mm"
public var filter: Bool = true
public var numberOfTransactions: Int = 5
}
public enum TransactionHistoryLeadingElement {
case none
case icon
case brandLogo
}Usage:
sdk.styleConfiguration.transactionHistoryViewProperties = TransactionHistoryViewProperties(
leadingElement: .icon,
groupByMonth: true,
timestampFormat: "MMM dd, yyyy",
filter: true,
numberOfTransactions: 10
)Spacing
Global spacing multiplier applied to paddings and gaps throughout the SDK.
// Default is 8pt
sdk.styleConfiguration.spacing = 12 // Increase spacing
sdk.styleConfiguration.spacing = 4 // Decrease spacingStyle Properties
CardListViewStyle
public struct CardListViewStyle {
public var internalHorizontalPadding: CGFloat = 16
public var internalVerticalPadding: CGFloat = 12
public var externalPadding: CGFloat = 16
public var internalGap: CGFloat = 16
public var radius: CGFloat = 12
}CardDetailsViewStyle
public struct CardDetailsViewStyle {
public let internalHorizontalPadding: CGFloat = 16
public let internalVerticalPadding: CGFloat = 12
public let externalPadding: CGFloat = 16
public let internalGap: CGFloat = 16
public let radius: CGFloat = 12
}TransactionHistoryViewStyle
public struct TransactionHistoryViewStyle {
public var internalHorizontalPadding: CGFloat = 16
public var internalVerticalPadding: CGFloat = 12
public var externalPadding: CGFloat = 16
public var internalGap: CGFloat = 16
public var radius: CGFloat = 12
}Applying Styles to Components
Global Application (Recommended)
Apply styles once at app initialization:
import SwiftUI
@main
struct MyApp: App {
let sdk: DigitalCardEngine
init() {
// Initialize SDK
sdk = try! DigitalCardEngine(
token: "your-token",
dceConfiguration: DceConfiguration(/* ... */),
totpCallback: { _ in /* ... */ }
)
// Apply global theme
applyCustomTheme()
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(sdk.styleConfiguration)
}
}
private func applyCustomTheme() {
// Customize palette
sdk.styleConfiguration.palette.secondary = Color(hex: 0x00A86B)
sdk.styleConfiguration.palette.success = Color(hex: 0x4CAF50)
// Customize spacing
sdk.styleConfiguration.spacing = 12
// Customize card list
sdk.styleConfiguration.cardListViewProperties = CardListViewProperties(
title: true,
actionButton: true,
dividers: true,
cardListLayout: .largeLayout
)
// Customize card details
sdk.styleConfiguration.cardDetailsViewProperties = CardDetailsViewProperties(
actionButton: true,
slider: false,
cardInfoLayout: .detailLayout
)
}
}Per-Component Customization
Pass style properties directly to individual components:
struct CustomStyledCardList: View {
let sdk: DigitalCardEngine
var body: some View {
try? sdk.getCardListView(
properties: CardListViewProperties(
title: false,
actionButton: true,
cardListLayout: .defaultLayout
),
style: CardListViewStyle(
internalHorizontalPadding: 20,
internalVerticalPadding: 16,
externalPadding: 24,
internalGap: 20,
radius: 16
),
onSelect: { card in /* ... */ },
onAddCard: { /* ... */ }
)
}
}Environment Object Pattern
Use SwiftUI's environment to propagate styling:
struct ThemedView: View {
let sdk: DigitalCardEngine
var body: some View {
NavigationStack {
ContentView()
}
.environmentObject(sdk.styleConfiguration)
}
}
struct ContentView: View {
@EnvironmentObject var styleConfig: StyleConfiguration
var body: some View {
VStack {
Text("Custom Styled")
.font(styleConfig.fonts.titleLarge.font)
.foregroundColor(styleConfig.palette.onSurface)
}
}
}Best Practices
- Apply globally: Set styles once at app startup via
sdk.styleConfiguration - Use semantic colors: Leverage the Palette system rather than hardcoding colors
- Maintain consistency: Keep spacing and typography consistent across screens
- Test accessibility: Ensure text contrasts meet WCAG standards
- Avoid per-component overrides: Only override when absolutely necessary
- Document custom themes: Keep a reference of your color/font choices
Complete Example
import SwiftUI
@main
struct DigitalCardApp: App {
let sdk: DigitalCardEngine
init() {
// Initialize SDK
let config = DceConfiguration(
clientId: 12345,
accountId: "account-id",
userId: "user-id",
apiKeyId: "api-key-id",
apiKey: "api-key"
)
sdk = try! DigitalCardEngine(
token: "auth-token",
dceConfiguration: config,
totpCallback: { cardId in
return "totp-secret"
}
)
// Apply comprehensive theme
configureTheme()
}
var body: some Scene {
WindowGroup {
ContentView(sdk: sdk)
.environmentObject(sdk.styleConfiguration)
}
}
private func configureTheme() {
// Colors
sdk.styleConfiguration.palette = Palette(
surface: Color.white,
onSurface: Color(hex: 0x1A1A1A),
onSurfaceVariant: Color(hex: 0x666666),
primary: Color(hex: 0x0019BF),
secondary: Color(hex: 0x00A86B),
success: Color(hex: 0x4CAF50),
outlineVariant: Color(hex: 0xE0E0E0),
surfaceContainerHighest: Color(hex: 0xF5F5F5),
surfaceContainerLow: Color(hex: 0xF9F9F9)
)
// Global settings
sdk.styleConfiguration.spacing = 12
// Card list preferences
sdk.styleConfiguration.cardListViewProperties = CardListViewProperties(
title: true,
actionButton: true,
dividers: true,
cardListLayout: .largeLayout
)
sdk.styleConfiguration.cardListViewStyle = CardListViewStyle(
internalHorizontalPadding: 16,
internalVerticalPadding: 12,
externalPadding: 16,
internalGap: 16,
radius: 12
)
// Card details preferences
sdk.styleConfiguration.cardDetailsViewProperties = CardDetailsViewProperties(
actionButton: true,
slider: false,
cardInfoLayout: .detailLayout
)
// Transaction history preferences
sdk.styleConfiguration.transactionHistoryViewProperties = TransactionHistoryViewProperties(
leadingElement: .icon,
groupByMonth: true,
timestampFormat: "MMM dd, yyyy",
filter: true,
numberOfTransactions: 10
)
}
}
struct ContentView: View {
let sdk: DigitalCardEngine
@EnvironmentObject var styleConfig: StyleConfiguration
var body: some View {
NavigationStack {
VStack {
Text("Digital Card Engine")
.font(styleConfig.fonts.titleLarge.font)
.foregroundColor(styleConfig.palette.onSurface)
try? sdk.getCardListView(
onSelect: { card in
// Handle selection
},
onAddCard: {
// Handle add card
}
)
}
}
}
}Troubleshooting
Styles not applying: Ensure you modify sdk.styleConfiguration after initialization but before rendering UI components.
Colors look wrong: Verify you're using Color(hex:) format with proper hex values.
Fonts not loading: Check that custom font files are included in the app bundle and properly registered in Info.plist.
Environment object not found: Ensure .environmentObject(sdk.styleConfiguration) is applied to the view hierarchy.
See Also
- Component Reference - Using styled components
- Data Models - Understanding component data
- Error Handling - Styling error states
Updated 3 months ago
