Theming

Theming — Apply your brand’s colors, fonts, and styles to Seam Mobile Components with SeamTheme.

Seam Mobile Components are white-label ready. You control appearance by providing a SeamTheme via the SwiftUI environment. The theme is a semantic palette composed of nested palettes—colors, fonts, keyCard, toast, and unlockCard—so you can brand globally or override locally.

All SeamComponents (e.g., SeamAccessView, SeamKeyCardView, SeamCredentialsView, SeamUnlockCardView) automatically read the theme from EnvironmentValues.seamTheme.


How theming works

  • Environment-driven: Inject a SeamTheme anywhere in your view hierarchy:

.environment(\.seamTheme, customTheme)
  • Defaults provided: If you don’t inject a theme, components use SeamTheme.default.

  • Partial overrides: Every nested palette supports .with(...) so you can change a few fields without redefining everything.


Quick start

Inject a theme at the root so all Seam components share a consistent look:

import SwiftUI
import SeamComponents

@main
struct MyApp: App {
    private let customTheme = SeamTheme(
        colors: .default.with(
            accent: .orange,
            error: .pink
        ),
        fonts: .default.with(
            largeTitle: .system(size: 36, weight: .bold)
        ),
        keyCard: .default.with(
            cornerRadius: 20 // see KeyCard palette
        )
    )

    var body: some Scene {
        WindowGroup {
            SeamAccessView()
                .environment(\.seamTheme, customTheme)
        }
    }
}

Local override

Scope a different look to a subsection of your UI:

let alertyToast = SeamTheme.Toast.default.with(
    background: .red.opacity(0.1),
    borderColor: .red,
    textColor: .primary
)

SeamAccessView()
    .environment(\.seamTheme, .default.with(
        toast: alertyToast
    ))

Theme structure

SeamTheme groups styling into five nested palettes. Each has:

  • A default value that matches iOS look & feel.

  • A memberwise initializer (for full control).

  • A with(...) builder to override specific fields.


Composing a theme

Use the top-level SeamTheme.with(...) to swap in any subset of palettes:

let theme = SeamTheme.default.with(
    colors: .default.with(accent: .indigo),
    fonts: .default.with(title2: .system(.title2, design: .rounded)),
    keyCard: .default.with(cornerRadius: 22),
    toast: .default.with(accentColor: .indigo),
    unlockCard: .default.with(progressColor: .indigo)
)

Then inject:

SeamAccessView()
    .environment(\.seamTheme, theme)

Dark mode

  • The defaults are light/dark adaptive by relying on system colors (e.g., Color(UIColor.systemBackground), .primary, .secondary).

  • When customizing, prefer dynamic colors or provide your own light/dark logic:

let colors = SeamTheme.Colors.default.with(
    primaryBackground: Color(light: .white, dark: .black)
)

Best practices

  • Start with defaults, then override selectively with .with(...).

  • Keep contrast high for accessibility; test in light and dark modes.

  • Brand consistently by driving accent, key button gradient, and toast accent from the same hue family.

  • Scope locally if a one-off component needs a different visual treatment.


API reference at a glance

  • SeamTheme.default — system-aligned theme

  • EnvironmentValues.seamTheme — environment key for theming

  • Builders:

    • SeamTheme.with(colors:fonts:keyCard:toast:unlockCard:)

    • SeamTheme.Colors.default.with(...)

    • SeamTheme.Fonts.default.with(...)

    • SeamTheme.KeyCard.default.with(...)

    • SeamTheme.Toast.default.with(...)

    • SeamTheme.UnlockCard.default.with(...)

Last updated

Was this helpful?