SwiftUI Components
Cuppa provides a comprehensive library of SwiftUI components that follow iOS Human Interface Guidelines while maintaining consistency across your application.
Component Library
Buttons
CuppaButton
A customizable button component with multiple styles:
import CuppaUI
struct ButtonExamples: View {
var body: some View {
VStack(spacing: 16) {
// Primary button
CuppaButton(
title: "Primary Action",
style: .primary,
action: { handleAction() }
)
// Secondary button
CuppaButton(
title: "Secondary Action",
style: .secondary,
action: { handleAction() }
)
// Destructive button
CuppaButton(
title: "Delete",
style: .destructive,
action: { confirmDelete() }
)
// Loading state
CuppaButton(
title: "Submit",
style: .primary,
isLoading: isSubmitting,
action: { submit() }
)
// Disabled state
CuppaButton(
title: "Disabled",
style: .primary,
isDisabled: true,
action: { }
)
}
.padding()
}
}
IconButton
Button with icon support:
CuppaIconButton(
icon: Image(systemName: "heart.fill"),
style: .primary,
action: { toggleFavorite() }
)
Form Inputs
TextField
Text input with validation and styling:
struct FormExample: View {
@State private var email = ""
@State private var name = ""
@State private var phone = ""
var body: some View {
Form {
CuppaTextField(
text: $email,
placeholder: "Email",
keyboardType: .emailAddress,
autocapitalization: .none,
validation: .email
)
CuppaTextField(
text: $name,
placeholder: "Full Name",
leadingIcon: Image(systemName: "person")
)
CuppaTextField(
text: $phone,
placeholder: "Phone",
keyboardType: .phonePad,
format: .phone
)
}
}
}
SecureField
Password input field:
@State private var password = ""
CuppaSecureField(
text: $password,
placeholder: "Password",
showToggle: true, // Show/hide password toggle
validation: .password
)
TextEditor
Multi-line text input:
@State private var notes = ""
CuppaTextEditor(
text: $notes,
placeholder: "Enter your notes",
minHeight: 100,
maxHeight: 300
)
Lists and Collections
CuppaList
Enhanced list component with built-in features:
struct ItemListView: View {
let items: [Item]
@State private var selectedItem: Item?
var body: some View {
CuppaList(
items,
selection: $selectedItem,
emptyState: {
EmptyStateView(
icon: "tray",
title: "No Items",
message: "Add your first item to get started"
)
}
) { item in
ItemRow(item: item)
}
.refreshable {
await refreshItems()
}
.searchable(text: $searchText)
}
}
Grid
Responsive grid layout:
CuppaGrid(
items: products,
columns: 2,
spacing: 16
) { product in
ProductCard(product: product)
}
Cards
Card
Container with elevation and rounded corners:
CuppaCard {
VStack(alignment: .leading, spacing: 12) {
Text("Card Title")
.font(.headline)
Text("Card content goes here")
.font(.body)
Divider()
HStack {
CuppaButton(title: "Action", style: .primary) { }
Spacer()
CuppaButton(title: "Cancel", style: .secondary) { }
}
}
.padding()
}
Modals and Sheets
BottomSheet
Sliding bottom sheet:
struct ContentView: View {
@State private var showSheet = false
var body: some View {
VStack {
CuppaButton(title: "Show Sheet", style: .primary) {
showSheet = true
}
}
.cuppaBottomSheet(isPresented: $showSheet) {
SheetContent()
}
}
}
struct SheetContent: View {
var body: some View {
VStack(spacing: 20) {
Text("Bottom Sheet")
.font(.headline)
Text("Content goes here")
CuppaButton(title: "Close", style: .secondary) {
// Close sheet
}
}
.padding()
}
}
Modal
Full-screen or custom modal:
.cuppaModal(isPresented: $showModal) {
ModalContent()
}
Alert
Custom alert dialog:
CuppaAlert(
isPresented: $showAlert,
title: "Confirm Action",
message: "Are you sure you want to proceed?",
primaryButton: .default("Confirm") {
confirmAction()
},
secondaryButton: .cancel()
)
Navigation
TabBar
Bottom tab navigation:
CuppaTabView {
HomeView()
.cuppaTab(title: "Home", icon: "house")
SearchView()
.cuppaTab(title: "Search", icon: "magnifyingglass")
ProfileView()
.cuppaTab(title: "Profile", icon: "person")
}
NavigationBar
Custom navigation bar:
CuppaNavigationStack {
ContentView()
.cuppaNavigationBar(title: "Home")
.cuppaNavigationBarItems(
leading: {
Button("Menu") { showMenu = true }
},
trailing: {
Button("Settings") { showSettings = true }
}
)
}
Indicators
Loading
Activity indicators:
// Spinner
CuppaLoadingSpinner(style: .large)
// Progress bar
CuppaProgressBar(progress: 0.7)
// Skeleton loader
CuppaSkeletonView {
VStack {
CuppaSkeletonLine(width: 200)
CuppaSkeletonLine(width: 150)
CuppaSkeletonCircle(size: 60)
}
}
Toast
Temporary notification:
struct ContentView: View {
@State private var showToast = false
var body: some View {
VStack {
CuppaButton(title: "Show Toast", style: .primary) {
showToast = true
}
}
.cuppaToast(
isPresented: $showToast,
message: "Action completed successfully",
type: .success,
duration: 3
)
}
}
Media
Image
Enhanced image component with loading states:
CuppaAsyncImage(
url: imageURL,
placeholder: {
ProgressView()
},
error: {
Image(systemName: "photo")
.foregroundColor(.gray)
}
)
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.clipShape(RoundedRectangle(cornerRadius: 12))
Video Player
Video playback component:
CuppaVideoPlayer(
url: videoURL,
autoplay: true,
controls: true
)
Theming
Apply custom themes to components:
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.cuppaTheme(
CuppaTheme(
primaryColor: .blue,
secondaryColor: .purple,
fontFamily: "SF Pro",
cornerRadius: 12,
spacing: 16
)
)
}
}
}
Component Modifiers
Cuppa provides custom view modifiers for common patterns:
// Rounded corners with shadow
myView
.cuppaCard(cornerRadius: 12, shadow: .medium)
// Shimmer loading effect
myView
.cuppaShimmer(isLoading: isLoading)
// Haptic feedback on tap
myButton
.cuppaHaptic(.light)
Accessibility
All Cuppa components include built-in accessibility support:
CuppaButton(
title: "Submit",
style: .primary,
accessibilityLabel: "Submit form",
accessibilityHint: "Double tap to submit the form"
) {
submit()
}
Next Steps
- Explore the full Components Reference
- Learn about Theming and Customization
- See iOS Examples