Button
A customizable button component with bouncy press animations, multiple variants, loading states, and icons.
Import
import PrettyUI
Basic Usage
PButton("Click Me") {
print("Button tapped!")
}
Variants
PButton supports 6 different visual variants:
// Primary - Main call-to-action
PButton("Primary").variant(.primary)
// Secondary - Less prominent actions
PButton("Secondary").variant(.secondary)
// Destructive - Dangerous actions (delete, remove)
PButton("Delete").variant(.destructive)
// Outline - Bordered, transparent background
PButton("Outline").variant(.outline)
// Ghost - No background, minimal styling
PButton("Ghost").variant(.ghost)
// Link - Text-only, link-style
PButton("Learn More").variant(.link)
| Variant | Background | Border | Best For |
|---|---|---|---|
.primary | Primary color | None | Main CTAs |
.secondary | Muted color | None | Secondary actions |
.destructive | Destructive color | None | Delete, cancel |
.outline | Card color | Border | Alternative actions |
.ghost | Transparent | None | Subtle actions |
.link | Transparent | None | Navigation, inline links |
Sizes
Three sizes are available:
PButton("Small").size(.sm) // Height: 36pt
PButton("Medium").size(.md) // Height: 44pt
PButton("Large").size(.lg) // Height: 52pt (default)
| Size | Height | Font Size | Padding |
|---|---|---|---|
.sm | 36pt | 15pt | 16pt horizontal |
.md | 44pt | 17pt | 24pt horizontal |
.lg | 52pt | 19pt | 24pt horizontal |
Full Width
Make a button span the full width of its container:
PButton("Full Width Button")
.variant(.primary)
.fullWidth()
Icons
Add SF Symbols icons to your buttons:
// Leading icon (default)
PButton("Create Wallet")
.icon("plus.circle.fill")
// Trailing icon
PButton("Continue")
.icon("arrow.right")
.iconPosition(.trailing)
Loading State
Show loading state with various spinner styles:
// Basic loading
PButton("Save")
.loading(isLoading)
// With custom loading text
PButton("Submit")
.loading(isLoading, text: "Submitting...")
// Different spinner positions
PButton("Processing")
.loading(isLoading)
.loadingPosition(.leading) // Before text
.loadingPosition(.trailing) // After text
.loadingPosition(.replace) // Replace text entirely
Spinner Styles
Customize the loading spinner:
PButton("Syncing")
.loading(true)
.spinnerStyle(.circular) // Default rotating circle
.spinnerStyle(.dots) // Bouncing dots
.spinnerStyle(.minimal) // Simple arc
.spinnerStyle(.orbit) // Orbiting dot
.spinnerStyle(.track) // Circle with track
Hide Text During Loading
PButton("Save")
.loading(true)
.hideTextWhenLoading() // Shows only spinner
Disabled State
PButton("Cannot Click")
.disabled()
Custom Colors
Override the default colors:
// Using Color values
PButton("Custom Colors")
.background(Color.purple)
.foreground(Color.white)
// Using ColorTokens (theme-aware)
PButton("Theme Colors")
.background(.success)
.foreground(.successForeground)
// Both at once
PButton("Styled")
.colors(background: Color.orange, foreground: Color.white)
Corner Radius
Control the button's corner radius:
PButton("Pill Shape").radius(.full) // Default for Sky theme
PButton("Rounded").radius(.lg)
PButton("Subtle").radius(.md)
PButton("Sharp").radius(.none)
Haptic Feedback
By default, PButton provides haptic feedback on iOS. You can disable it:
PButton("No Haptics")
.haptics(false)
Custom Sizing
Set explicit dimensions:
PButton("Fixed Width")
.width(200)
PButton("Fixed Height")
.height(60)
PButton("Fixed Size")
.frame(width: 150, height: 50)
Font Weight
Customize the font weight:
PButton("Bold").fontWeight(.bold)
PButton("Light").fontWeight(.light)
Combining Modifiers
Chain multiple modifiers for complex buttons:
PButton("Create Wallet") {
handleCreateWallet()
}
.variant(.primary)
.icon("plus.circle.fill")
.size(.lg)
.fullWidth()
.loading(isCreating)
.loadingPosition(.trailing)
.spinnerStyle(.dots)
Real-World Examples
Onboarding Buttons
VStack(spacing: 12) {
PButton("Create a New Wallet") {
// Handle create
}
.variant(.primary)
.icon("plus")
.fullWidth()
PButton("Add an Existing Wallet") {
// Handle import
}
.variant(.outline)
.fullWidth()
}
Form Submit Button
PButton(isLoading ? "Saving..." : "Save Changes") {
saveForm()
}
.variant(.primary)
.loading(isLoading)
.loadingPosition(.leading)
.disabled(!formIsValid)
.fullWidth()
Destructive Action
PButton("Delete Account") {
showDeleteConfirmation = true
}
.variant(.destructive)
.icon("trash")
API Reference
Initializer
public init(_ title: String, action: @escaping () -> Void = {})
Modifiers
| Modifier | Type | Description |
|---|---|---|
.variant(_:) | PButtonVariant | Visual style |
.size(_:) | PButtonSize | Button size |
.radius(_:) | RadiusSize | Corner radius |
.fullWidth(_:) | Bool | Expand to full width |
.loading(_:) | Bool | Show loading state |
.loading(_:text:) | Bool, String | Loading with custom text |
.loadingPosition(_:) | LoadingPosition | Spinner position |
.hideTextWhenLoading(_:) | Bool | Hide text during loading |
.spinnerStyle(_:) | PSpinnerStyle | Loading spinner style |
.spinnerSize(_:) | PSpinnerSize | Spinner size |
.disabled() | — | Disable button |
.icon(_:) | String | SF Symbol name |
.iconPosition(_:) | IconPosition | Icon placement |
.haptics(_:) | Bool | Enable/disable haptics |
.background(_:) | Color or ColorToken | Background color |
.foreground(_:) | Color or ColorToken | Text/icon color |
.colors(background:foreground:) | Color/ColorToken | Both colors |
.width(_:) | CGFloat | Fixed width |
.height(_:) | CGFloat | Fixed height |
.frame(width:height:) | CGFloat? | Fixed dimensions |
.fontWeight(_:) | Font.Weight | Text weight |
Enums
PButtonVariant
.primary— Main call-to-action.secondary— Secondary actions.destructive— Dangerous actions.outline— Bordered style.ghost— Minimal style.link— Link style
PButtonSize
.sm— Small (36pt).md— Medium (44pt).lg— Large (52pt).icon— Icon-only (40pt)
LoadingPosition
.leading— Before text.trailing— After text.replace— Replace text
IconPosition
.leading— Before text.trailing— After text
Accessibility
PButton automatically:
- Supports VoiceOver with the button title as the accessibility label
- Respects
accessibilityReduceMotionfor animations - Shows disabled state visually with reduced opacity