Text Field

A polished text input component featuring floating labels, smooth animations, validation states, and icons.

Import

import PrettyUI

Basic Usage

@State private var email = ""

PTextField("Email", text: $email)

Variants

Three visual variants are available:

// Outlined - bordered (default)
PTextField("Email", text: $email)
    .variant(.outlined)

// Filled - background color
PTextField("Search", text: $query)
    .variant(.filled)

// Underlined - bottom border only
PTextField("Name", text: $name)
    .variant(.underlined)
VariantStyleBest For
.outlinedBorderForms, default use
.filledBackgroundSearch bars, compact forms
.underlinedBottom lineMinimal, elegant forms

Sizes

Three sizes are available:

PTextField("Small", text: $text).size(.sm)   // 48pt height
PTextField("Medium", text: $text).size(.md)  // 56pt height (default)
PTextField("Large", text: $text).size(.lg)   // 64pt height

Icons

Add leading and/or trailing icons:

// Leading icon
PTextField("Email", text: $email)
    .leadingIcon("envelope")

// Trailing icon
PTextField("Website", text: $website)
    .trailingIcon("arrow.up.right")

// Both
PTextField("Search", text: $query)
    .leadingIcon("magnifyingglass")
    .trailingIcon("mic.fill")

Secure Text (Password)

Create password fields with visibility toggle:

PTextField("Password", text: $password)
    .secure()
    .leadingIcon("lock")

The field automatically shows an eye icon to toggle visibility.

Floating Label

By default, PTextField uses a floating label that animates up when focused or filled:

// Enable (default)
PTextField("Email", text: $email)
    .floatingLabel(true)

// Disable for static placeholder
PTextField("Enter your name", text: $name)
    .floatingLabel(false)

Clear Button

Show a clear button when text is present:

PTextField("Search", text: $query)
    .clearButton()  // Enabled by default
    .clearButton(false)  // Disable

Validation States

Error State

PTextField("Email", text: $email)
    .leadingIcon("envelope")
    .error(emailError)  // Pass nil to clear

// Example with validation
.error(isValidEmail(email) ? nil : "Please enter a valid email")

Success State

PTextField("Username", text: $username)
    .leadingIcon("person")
    .success("Username is available!")

Helper Text

PTextField("Email", text: $email)
    .helper("We'll never share your email")

Character Limit

Show a character counter with limit:

PTextField("Bio", text: $bio)
    .maxCharacters(100)

The counter turns red when over the limit.

Keyboard Configuration (iOS)

PTextField("Email", text: $email)
    .keyboard(.emailAddress)
    .autocapitalization(.never)

PTextField("Phone", text: $phone)
    .keyboard(.phonePad)

PTextField("Amount", text: $amount)
    .keyboard(.decimalPad)

Submit Handling

Handle keyboard submit action:

PTextField("Search", text: $query)
    .submitLabel(.search)
    .onSubmit {
        performSearch()
    }

Available submit labels: .done, .go, .search, .send, .next, .continue

Disabled State

PTextField("Email", text: .constant("john@example.com"))
    .disabled()

Custom Colors

Override the default colors:

// Custom focus color
PTextField("Email", text: $email)
    .focusColor(.purple)

// Custom background
PTextField("Search", text: $query)
    .backgroundColor(Color.gray.opacity(0.1))

// All custom colors
PTextField("Custom", text: $text)
    .colors(
        focus: .green,
        background: Color.green.opacity(0.1),
        foreground: .green,
        placeholder: Color.green.opacity(0.5)
    )

Search Field

PrettyUI includes a pre-configured search field:

@State private var searchQuery = ""

PSearchField("Search wallets...", text: $searchQuery) {
    performSearch()
}

This is equivalent to:

PTextField("Search", text: $query)
    .variant(.filled)
    .leadingIcon("magnifyingglass")
    .floatingLabel(false)
    .clearButton()
    .radius(.full)

Labeled Text Field

For forms with static labels above the field:

PLabeledTextField(
    "Email Address",
    placeholder: "john@example.com",
    text: $email,
    isRequired: true
)

Real-World Examples

Login Form

VStack(spacing: 16) {
    PTextField("Email", text: $email)
        .leadingIcon("envelope")
        .keyboard(.emailAddress)
        .autocapitalization(.never)
        .error(emailError)
    
    PTextField("Password", text: $password)
        .secure()
        .leadingIcon("lock")
        .error(passwordError)
    
    PButton("Sign In") {
        login()
    }
    .variant(.primary)
    .fullWidth()
    .loading(isLoading)
}

Profile Form

VStack(spacing: 20) {
    PLabeledTextField("Full Name", text: $name, isRequired: true)
    
    PLabeledTextField("Email", text: $email, isRequired: true)
        .keyboard(.emailAddress)
    
    PTextField("Bio", text: $bio)
        .maxCharacters(150)
        .helper("Tell us about yourself")
}

Search with Suggestions

VStack {
    PSearchField("Search products...", text: $query) {
        search()
    }
    
    if !query.isEmpty {
        ForEach(suggestions) { suggestion in
            Text(suggestion.name)
        }
    }
}

API Reference

Initializer

public init(_ label: String, text: Binding<String>)

Modifiers

ModifierTypeDescription
.variant(_:)PTextFieldVariantVisual style
.size(_:)PTextFieldSizeField size
.radius(_:)RadiusSizeCorner radius
.secure(_:)BoolPassword mode
.floatingLabel(_:)BoolFloating label animation
.clearButton(_:)BoolShow clear button
.maxCharacters(_:)IntCharacter limit
.leadingIcon(_:)StringSF Symbol name
.trailingIcon(_:)StringSF Symbol name
.error(_:)String?Error message
.success(_:)String?Success message
.helper(_:)String?Helper text
.disabled(_:)BoolDisable field
.keyboard(_:)UIKeyboardTypeKeyboard type (iOS)
.autocapitalization(_:)TextInputAutocap...Auto-caps (iOS)
.submitLabel(_:)SubmitLabelReturn key label
.onSubmit(_:)() -> VoidSubmit action
.focusColor(_:)ColorFocus ring color
.backgroundColor(_:)ColorBackground color
.foregroundColor(_:)ColorText color
.placeholderColor(_:)ColorPlaceholder color

Enums

PTextFieldVariant

  • .outlined — Bordered (default)
  • .filled — Background color
  • .underlined — Bottom line only

PTextFieldSize

  • .sm — Small (48pt)
  • .md — Medium (56pt, default)
  • .lg — Large (64pt)

Helper Components

PSearchField

PSearchField(_ placeholder: String, text: Binding<String>, onSubmit: (() -> Void)?)

Pre-configured search field with pill shape and magnifying glass icon.

PLabeledTextField

PLabeledTextField(
    _ label: String,
    placeholder: String = "",
    text: Binding<String>,
    isRequired: Bool = false
)

Text field with a static label above (non-floating).

Accessibility

PTextField automatically:

  • Announces the label and current value for VoiceOver
  • Indicates error and success states
  • Shows character count for limited fields
  • Respects reduced motion preferences