SwiftUI

SwiftUI integration starts with TerminalViewState. It owns the controller, exposes observable terminal state, and tracks the current TerminalSurface after a platform view attaches.

State

import SwiftUI
import GhosttyTerminal

struct TerminalScreen: View {
    @StateObject private var terminal = TerminalViewState()

    var body: some View {
        TerminalSurfaceView(context: terminal)
            .navigationTitle(terminal.title)
    }
}

Observable properties include title, surfaceSize, isFocused, bellCount, lastBellAt, desktop notification metadata, workingDirectory, and command-finished metadata.

View

TerminalSurfaceView embeds the platform terminal view and adopts the current SwiftUI color scheme. This wrapper requires iOS 15, macOS 13, Mac Catalyst 15, or visionOS 1.

TerminalSurfaceView(context: terminal)
    .onAppear {
        terminal.configuration = TerminalSurfaceOptions(
            backend: .inMemory(session),
            fontSize: 13,
            workingDirectory: "/"
        )
    }

Input

Input takes two paths, and they are not interchangeable. sendKey(_:) presses a key: the event takes libghostty's key path, so the terminal's key encoding applies (legacy, modifyOtherKeys, kitty). paste(text:) is the text path: a program that enabled bracketed paste receives it framed as a paste, so a \r in it lands in the shell's edit line instead of running the command. Both return true when Ghostty accepts the input; call them after the surface attaches.

@discardableResult
func run(_ command: String) -> Bool {
    terminal.paste(text: command) && terminal.sendKey(.enter)
}

terminal.sendKey(.c, modifiers: .ctrl)              // interrupt
terminal.sendKey(.tab, modifiers: .shift)           // back-tab
terminal.sendKey(TerminalKeyPress(typing: "~")!)    // Shift+backquote on a US layout

TerminalKey covers libghostty's full key set and uses the W3C UI Events code names. Keys with no macOS keycode (media keys, numpad extras) report hasPlatformKeycode == false and are rejected. send(_:) is the deprecated name of paste(text:).

Configuration

Use fluent configuration for common Ghostty settings, and custom(_:_:) for additional Ghostty config keys.

let config = TerminalConfiguration.default
    .fontFamily("SF Mono")
    .fontSize(13)
    .windowPaddingX(8)
    .windowPaddingY(6)
    .custom("shell-integration", "detect")

terminal.setTerminalConfiguration(config)