# Integration Tiers | Swift AI Autocomplete Docs

> For the complete documentation index, see [llms.txt](https://ai-autocomplete.com/llms.txt). A markdown version of any page on this site is available by appending `.md` to its URL path — the homepage is at `/index.md`.

Integration Tiers guide for integrating the AI Autocomplete SDK with Swift. Code examples, setup, and API reference.

Source: https://ai-autocomplete.com/docs/swift/integration-tiers

---

Three ways in — the drop-in view, the shared controller with your own input, or the fully headless core.

Tier 1

### Full view

AIAutocomplete (SwiftUI) or AIAutocompleteView (UIKit). The SDK owns the input, pills, dropdown, and all state.

**Use when:** you want autocomplete working in minutes with stock UI.

Tier 2

### Your input + SDK dropdown

You own the text field; the SDK renders its dropdown next to it. Wire text through controller.textBinding and float the dropdown with .aiAutocompleteDropdown(_:).

**Use when:** you have a custom input (rich editor, search bar, existing form field) but want the stock dropdown.

Tier 3

### Headless

AIAutocompleteCore only. The @Observable controller exposes all state and actions; you render everything yourself.

**Use when:** you need full control over rendering on top of the SDK's state machine.

## Tier 1 — Full view

One view, no wiring. Lifecycle is automatic — it starts fetching on appear and stops on disappear. Tapping the submit button submits and resets for the next query.

**ComposerView.swift**

```swift
import AIAutocompleteCore
import AIAutocompleteSwiftUI
import SwiftUI

struct ComposerView: View {
    @FocusState private var isFocused: Bool

    var body: some View {
        AIAutocomplete(configuration: .init(
            apiConfig: .apiKey(.init(apiKey: "pk_v1_your_public_key")),
            onSubmit: { result in print(result.query) }
        ))
        .submitButton {
            Image(systemName: "arrow.up")
                .font(.system(size: 15, weight: .semibold))
                .foregroundStyle(.white)
                .frame(width: 32, height: 32)
                .background(.black, in: .circle)
        }
        .focused($isFocused)
        .padding()
    }
}
```

submitButton supplies visuals only — the SDK wires the tap to submit + reset. focused bridges the input's first-responder state to a @FocusState binding, in both directions.

### UIKit

AIAutocompleteView is the same Tier 1 surface for UIKit. It sizes itself via intrinsicContentSize — pin the edges and let it grow. Set submitButtonView for a custom button, or showsSubmitButton = false to hide it.

**ComposerViewController.swift**

```swift
import AIAutocompleteCore
import AIAutocompleteUIKit
import UIKit

final class ComposerViewController: UIViewController {
    private lazy var autocomplete = AIAutocompleteView(
        configuration: .init(
            apiConfig: .apiKey(.init(apiKey: "pk_v1_your_public_key")),
            onSubmit: { result in print(result.query) }
        )
    )

    override func viewDidLoad() {
        super.viewDidLoad()
        autocomplete.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(autocomplete)
        NSLayoutConstraint.activate([
            autocomplete.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
            autocomplete.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
            autocomplete.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
        ])
    }
}
```

Both views start fetching when they join a window and stop when they leave it — no lifecycle calls needed in either framework.

### Detached dropdown — full input, your anchor

When the input sits inside a larger container — a card with attachment or action buttons — the dropdown should usually align to the container's edge, not the bare input. Keep the full pill input, opt it out of its built-in dropdown, and anchor the dropdown to any view; both read the same controller. SwiftUI uses .dropdownHidden(); UIKit passes showsDropdown: false.

**DetachedDropdown.swift**

```swift
// SwiftUI — the input opts out of its built-in dropdown;
// the container anchors it instead. Both read one controller.
VStack {
    AIAutocomplete(controller: controller)
        .dropdownHidden()
    actionButtonRow
}
.aiAutocompleteDropdown(controller)

// UIKit — the same shape via showsDropdown
let input = AIAutocompleteView(controller: controller, showsDropdown: false)
let dropdown = AIAutocompleteDropdownView(controller: controller)
// Add both to your hierarchy; pin the dropdown to the container's edge.
```

## Tier 2 — Your input, SDK dropdown

Hold the controller yourself (@State), bind your field's text to controller.textBinding, forward focus with setFocused(_:), and float the dropdown over the field with .aiAutocompleteDropdown(_:). The dropdown sizes itself and clamps to the space above the keyboard.

**CustomComposer.swift**

```swift
import AIAutocompleteCore
import AIAutocompleteSwiftUI
import SwiftUI

struct CustomComposer: View {
    @State private var controller = AIAutocompleteController(
        configuration: .init(apiConfig: .apiKey(.init(apiKey: "pk_v1_your_public_key")))
    )
    @FocusState private var isFocused: Bool

    var body: some View {
        VStack(spacing: 12) {
            TextField("Create a", text: controller.textBinding)
                .textFieldStyle(.roundedBorder)
                .focused($isFocused)
                .onChange(of: isFocused) { _, focused in
                    controller.setFocused(focused)
                }
                .aiAutocompleteDropdown(controller)

            Button("Submit") {
                controller.submitAndReset()
            }
        }
        .padding()
    }
}
```

Prefer placing the dropdown yourself (e.g. in a stack)? Use the standalone AIAutocompleteDropdown(controller:) view instead of the modifier — same behavior, your layout.

UIKit equivalent: create an AIAutocompleteController, drive it from your text view, and add AIAutocompleteDropdownView(controller:) to your hierarchy. Its moveHighlight / selectHighlighted helpers support hardware-keyboard navigation.

Always reset after submitting

Tier 1 resets automatically. With your own submit flow, call submitAndReset() — or submit() then reset(). Reset clears the input and rotates the per-session ID so the server's history stays accurate; skipping it degrades suggestion quality on later submissions.

## Tier 3 — Headless

Import only AIAutocompleteCore and render from the controller's observable state: segments for the input's text-and-pill spans, filteredOptions for the option list, isDropdownOpen for visibility. Call start() when your UI appears.

**HeadlessComposer.swift**

```swift
import AIAutocompleteCore
import SwiftUI

struct HeadlessComposer: View {
    @State private var controller = AIAutocompleteController(
        configuration: .init(apiConfig: .apiKey(.init(apiKey: "pk_v1_your_public_key")))
    )

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            TextField("Create a", text: controller.textBinding)
                .onSubmit { controller.submitAndReset() }

            if controller.isDropdownOpen {
                ForEach(controller.filteredOptions, id: \.text) { option in
                    Button(option.text) {
                        controller.selectOption(option)
                    }
                }
            }
        }
        .onAppear { controller.start() }
        .onDisappear { controller.stop() }
    }
}
```

The controller is @MainActor and @Observable — SwiftUI views that read it re-render automatically; UIKit consumers can observe it with withObservationTracking.
