# Customization

The Incode iOS SDK is highly customizable. You can match onboarding flows to your brand and product. This page covers what you can change, including:

- Theme colors and fonts
- Buttons, labels, and other UI elements
- A custom logo
- Runtime theme switching
- Localization, including dynamic and runtime language switching
- V2 theme and UX configuration

***

## Get Started

Most integrations only need colors, fonts, and a logo. Consult the other sections when you have a specific need.

On iOS, all theming is done in Swift at runtime. There is no build-time resource system (such as Android's `colors.xml` or `styles.xml`). Instead, you configure a small set of public types and assign them to `IncdTheme` (V1) or the V2 properties. The V1 (UIKit) screens read from `IncdTheme.current` (a `ThemeConfiguration`), while the newer V2 (SwiftUI) screens read from `IncdTheme.typography`, `IncdTheme.colorPalette`, `IncdTheme.displayMode`, and `IncdTheme.components`. A single JSON blob passed to `IncdTheme.loadJsonTheme(_:)` populates both systems. This page documents both.

| Task                                                      | Section                                                               |
| --------------------------------------------------------- | --------------------------------------------------------------------- |
| Recolor the SDK and apply your fonts                      | [Customize Theme Colors and Fonts](#customize-theme-colors-and-fonts) |
| Display your logo                                         | [Add a Custom Logo](#add-a-custom-logo)                               |
| Change button shape, size, color, and style               | [Customize Buttons](#customize-buttons)                               |
| Restyle labels, the selfie background, and other elements | [Customize Other UI Elements](#customize-other-ui-elements)           |
| Swap the theme at runtime based on user preference        | [Configure Runtime Styles](#configure-runtime-styles)                 |
| Change any on-screen text, particularly for translation   | [Localize Display Text](#localize-display-text)                       |
| Theme the V2 (SwiftUI) modules                            | [Configure V2 Theme and UX](#configure-v2-theme-and-ux)               |

***

## Customize Theme Colors and Fonts

The V1 (UIKit) screens read colors, fonts, buttons, and labels from `IncdTheme.current`, a `ThemeConfiguration`. To customize them, copy the current theme, change the properties you need, and assign it back before you start onboarding.

<Callout icon="📘" theme="info">
  ### Note

  Set the theme before you start a flow. Assigning `IncdTheme.current` (or any of the V2 properties) takes effect on screens presented afterward.
</Callout>

### Colors

`ThemeConfiguration.colors` is a `ColorsConfiguration` with the following properties:

| Property              | Purpose                                                                     |
| --------------------- | --------------------------------------------------------------------------- |
| `primary`             | Primary color for all modules.                                              |
| `accent`              | Accent color for all modules.                                               |
| `background`          | Background color for all modules.                                           |
| `secondaryBackground` | Secondary background, used when a view sits on top of the background.       |
| `success`             | Success color.                                                              |
| `error`               | Error or destructive color.                                                 |
| `warning`             | Warning color.                                                              |
| `cancel`              | Color used for the cancel (X) button.                                       |
| `cancelDark`          | Cancel (X) button color on dark backgrounds, such as during a Video Selfie. |
| `disabled`            | Color for disabled controls.                                                |
| `primaryDark`         | Primary color for dark backgrounds.                                         |

```swift
import IncdOnboarding
import UIKit

var theme = IncdTheme.current
theme.colors.primary = UIColor(red: 0.12, green: 0.16, blue: 0.24, alpha: 1)
theme.colors.accent = UIColor(red: 0.0, green: 0.42, blue: 1.0, alpha: 1)
theme.colors.background = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)
theme.colors.success = UIColor(red: 0.05, green: 0.84, blue: 0.64, alpha: 1)
theme.colors.error = UIColor(red: 1.0, green: 0.36, blue: 0.44, alpha: 1)
theme.colors.warning = UIColor(red: 0.95, green: 0.67, blue: 0.24, alpha: 1)
IncdTheme.current = theme
```

### Fonts

`ThemeConfiguration.fonts` is a `FontsConfiguration`. Construct one with the roles you want to override; any role you omit keeps its default.

```swift
var theme = IncdTheme.current
theme.fonts = FontsConfiguration(
    title: UIFont(name: "YourFont-Bold", size: 24),
    subtitle: UIFont(name: "YourFont-Medium", size: 18),
    body: UIFont(name: "YourFont-Regular", size: 16),
    buttonBig: UIFont(name: "YourFont-Bold", size: 18)
)
IncdTheme.current = theme
```

`FontsConfiguration` exposes the following roles:

- `title`

- `bigTitle`

- `hugeTitle`

- `subtitle`

- `boldedSubtitle`

- `smallSubtitle`

- `smallBoldedSubtitle`

- `info`

- `body`

- `boldedBody`

- `buttonBig`

- `buttonMedium`

- `buttonSmall`

- `textFieldBig`

- `textFieldMedium`

- `feedbackSmall`

- `feedbackBig`

***

## Add a Custom Logo

Show a custom logo at the top of supported screens by setting `IncdTheme.logo`. It is a `UIImage?`. If you do not set it, the SDK uses the default Incode logo.

```swift
IncdTheme.logo = UIImage(named: "my_logo")
```

The Video Selfie module lets you show a custom logo just for its own screens. Set it on the module's `VideoSelfieConfiguration` before adding the module to your flow:

```swift
let config = VideoSelfieConfiguration()
config.setLogo(UIImage(named: "my_video_selfie_logo"))
flowConfig.addVideoSelfie(videoSelfieConfiguration: config)
```

The Video Selfie logo applies only to that module's capture screens. All other supported screens use the generic `IncdTheme.logo`. See [Video Selfie](https://developer.incode.com/docs/module-video-selfie) for the full module configuration.

***

## Customize Buttons

`ThemeConfiguration.buttons` is a `ButtonsConfiguration` with one `ButtonConfiguration` per button role: `primary`, `secondary`, `text`, `help`, and `chooser`.

Each `ButtonConfiguration` has:

- `states`: per-state styling for `normal`, `highlighted`, and `disabled`, each a `ButtonThemedState`.
- `big` and `medium`: size variants, each a `ButtonSizeVariant`.

A `ButtonThemedState` exposes:

- `backgroundColor`

- `borderColor`

- `borderWidth`

- `cornerRadius`

- `textColor`

- `alpha`

- `shadowColor`

- `shadowOffset`

- `shadowOpacity`

- `shadowRadius`

- `iconImageName` (optional)

- `iconTintColor` (optional)

- `iconPosition` (optional)

- `iconPadding` (optional)

A `ButtonSizeVariant` exposes `height`, `minWidth`, `contentInsets`, and `kerning`.

```swift
var theme = IncdTheme.current

// Primary button: normal state
theme.buttons.primary.states.normal.backgroundColor = UIColor(red: 0.0, green: 0.42, blue: 1.0, alpha: 1)
theme.buttons.primary.states.normal.textColor = .white
theme.buttons.primary.states.normal.cornerRadius = 12
theme.buttons.primary.states.normal.borderWidth = 0

// Primary button: disabled state
theme.buttons.primary.states.disabled.backgroundColor = UIColor(white: 0.9, alpha: 1)
theme.buttons.primary.states.disabled.textColor = UIColor(white: 0.6, alpha: 1)

// Primary button: big size variant
theme.buttons.primary.big.height = 64
theme.buttons.primary.big.minWidth = 200

// Secondary button
theme.buttons.secondary.states.normal.backgroundColor = .white
theme.buttons.secondary.states.normal.borderColor = UIColor(red: 0.12, green: 0.16, blue: 0.24, alpha: 1)
theme.buttons.secondary.states.normal.borderWidth = 1
theme.buttons.secondary.states.normal.cornerRadius = 12

IncdTheme.current = theme
```

***

## Customize Other UI Elements

Colors, fonts, and buttons cover most use cases. If you need more control, the theme exposes label styling and per-component configuration.

### Labels

`ThemeConfiguration.labels` is a `LabelsConfiguration` with one `LabelConfiguration` per text role: `title`, `secondaryTitle`, `subtitle`, `secondarySubtitle`, `smallSubtitle`, `info`, `secondaryInfo`, `body`, `secondaryBody`, and `code`. Each `LabelConfiguration` exposes `textColor`, `textAlignment`, and `kerning`.

```swift
var theme = IncdTheme.current
theme.labels.title.textColor = UIColor(red: 0.12, green: 0.16, blue: 0.24, alpha: 1)
theme.labels.body.textColor = UIColor(white: 0.39, alpha: 1)
theme.labels.info.textAlignment = .center
IncdTheme.current = theme
```

### Selfie and Video Selfie

`ThemeConfiguration.customComponents` groups per-component styling. Two components are commonly customized:

- The [Selfie](https://developer.incode.com/docs/module-selfie) camera background is white by default, which helps in low-light conditions. Change it with `SelfieThemeConfiguration`:
  ```swift
  var theme = IncdTheme.current
  theme.customComponents.selfie = SelfieThemeConfiguration(background: .white)
  IncdTheme.current = theme
  ```

- The [Video Selfie](https://developer.incode.com/docs/module-video-selfie) overlay and progress bar are configured with `VideoSelfieThemeConfiguration`:
  ```swift
  var theme = IncdTheme.current
  theme.customComponents.videoSelfie = VideoSelfieThemeConfiguration(
      overlayColor: .black,
      overlayAlpha: 0.44,
      progressBarColor: UIColor.white.withAlphaComponent(0.5),
      progressBarSelectedColor: .white
  )
  IncdTheme.current = theme
  ```

### Other custom components

`ThemeConfiguration.customComponents` also exposes `cameraFeedback`, `idCaptureHelp`, `idSideLabel`, `separator`, `signature`, `idAutocaptureCountdownConfiguration`, and `idCaptureFrame`. Assign a configured instance of each type to change the matching component. For their individual properties, see [API Reference](https://developer.incode.com/docs/ios-api-reference).

***

## Configure Runtime Styles

Because the theme is plain Swift state, you can change it at runtime: for example, to switch styles based on a user's preference. Assign a new value to `IncdTheme.current` (or to the V2 properties) at any point before the next screen is presented.

```swift
func applyHighContrastTheme() {
    var theme = IncdTheme.current
    theme.colors.primary = .black
    theme.colors.accent = .black
    theme.colors.background = .white
    IncdTheme.current = theme
}
```

To load a full theme from JSON at runtime, use `IncdTheme.loadJsonTheme(_:)`. See [Configure V2 Theme and UX](#configure-v2-theme-and-ux) for the JSON format.

```swift
let jsonString = "<THEME_JSON_STRING>"
IncdTheme.loadJsonTheme(jsonString)
```

To reset everything back to Incode's defaults, call:

```swift
IncdTheme.loadDefaultTheme()
```

***

## Localize Display Text

There are three ways to change the text the SDK displays:

- [Override the bundled strings](#override-bundled-strings) at build time
- Replace strings programmatically with [dynamic localization](#dynamic-localization)
- [Switch](#runtime-localization) the SDK language at runtime

The SDK ships default text for five locales: German, English, Spanish, Hebrew, and Portuguese (`de`, `en`, `es`, `he`, `pt`).

String keys follow a dotted namespace, for example `incdOnboarding.global.button.continue`, `incdOnboarding.global.button.cancel`, and `incdOnboarding.global.dialog.ok`.

### Override Bundled Strings

Point the SDK at your own `.strings` resources. Set the bundle that contains your `Localizable.strings`, and optionally a custom file name (without the `.strings` extension):

```swift
IncdLocalization.localizationBundle = Bundle.main
IncdLocalization.localizationStringsFile = "IncodeStrings" // uses IncodeStrings.strings
```

If you set neither, the SDK reads `Localizable.strings` from the main bundle, then falls back to its own bundled strings.

### Dynamic Localization

Override strings programmatically by assigning a dictionary of key/value pairs to `IncdLocalization.current`. Values in this dictionary take priority over the bundled localization.

```swift
IncdLocalization.current = [
    "incdOnboarding.global.button.continue": "Proceed",
    "incdOnboarding.global.dialog.ok": "Got it"
]
```

By default, keys not present in `IncdLocalization.current` fall back to the bundled localization. You can disable that fallback, though this is recommended only for testing:

```swift
IncdLocalization.disableFallback = true
```

### Runtime Localization

Change the SDK language at runtime by setting the preferred language. English is used if the requested language is not bundled.

```swift
IncdLocalization.localizationLanguage = "pt"
```

`IncdOnboardingManager.localizationLanguage` is deprecated and forwards to `IncdLocalization.localizationLanguage`. Use `IncdLocalization.localizationLanguage` directly.

***

## Configure V2 Theme and UX

The V2 (SwiftUI) screens are themed separately from the V1 configuration described above. You configure them with JSON: a theme JSON passed to `IncdTheme.loadJsonTheme(_:)`, and a UX JSON passed to `IncdUXConfig.loadUXConfig(_:)`.

### Theme Configuration via JSON

The theme JSON supports `displayMode`, `typography`, `colorPalette`, and `components`. On iOS, font families are nested under an `ios` key.

<Accordion title="View an example theme JSON">
  ```swift
  let json = """
  {
    "displayMode": "light",
    "typography": {
      "family": {
        "text": {
          "ios": {
            "regular": "DMSans-Regular",
            "medium": "DMSans-Medium",
            "bold": "DMSans-Bold"
          }
        },
        "display": {
          "ios": {
            "extraBold": "DMSans-ExtraBold"
          }
        }
      },
      "letterSpacing": {
        "none": 0,
        "medium": -0.5,
        "large": -1.0,
        "extraLarge": -1.5
      }
    },
    "colorPalette": {
      "neutralLight": "#ffffff",
      "neutralDark": "#000000",
      "brand50": "#e5f0ff",
      "brand200": "#99c3ff",
      "brand300": "#66a6ff",
      "brand400": "#3388ff",
      "brand500": "#006aff",
      "brand600": "#0055cc",
      "brand900": "#21273b",
      "gray50": "#FCFCFD",
      "gray100": "#EBECEF",
      "gray200": "#C6C8D2",
      "gray300": "#A3A8B8",
      "gray500": "#60667C",
      "gray700": "#3A3E4B",
      "gray800": "#262831",
      "gray900": "#14151A",
      "gray1000": "#000000",
      "brandSecondary50": "#F2E2FE",
      "brandSecondary500": "#820AD1",
      "negative50": "#FFF0F0",
      "negative400": "#FF5A5F",
      "negative500": "#E71111",
      "negative950": "#240001",
      "warning50": "#FFF7EB",
      "warning400": "#FFB647",
      "warning500": "#FF9900",
      "warning950": "#523100",
      "positive50": "#E4FBF0",
      "positive400": "#45B380",
      "positive500": "#189F60",
      "positive950": "#0C5030",
      "focus400": "#0099FF",
      "focus500": "#006AFF"
    },
    "components": {
      "buttons": [
        {
          "style": "primary",
          "surface": {
            "default": ["#000000", "#E8E8E8"],
            "hover": "#04FF5C",
            "pressed": "#00B540",
            "disabled": ["#EBECEF", "#000000"]
          },
          "text": {
            "default": ["#FFFFFF", "#000000"],
            "disabled": ["#959595", "#666666"]
          },
          "border": {
            "color": {
              "default": "#00D149"
            },
            "width": 0,
            "radius": 15
          }
        }
      ]
    }
  }
  """
  ```
</Accordion>

Apply it to the SDK:

```swift
IncdTheme.loadJsonTheme(json)
```

Note:

- `displayMode` can be `"light"`, `"dark"`, or `"system"`. If not set, the default is `"light"`.
- Font families are nested under `ios`. The font names must resolve to fonts available to your app (bundled and declared, or system fonts).
- Color tokens use hex strings. Both `#RRGGBB` and `#AARRGGBB` (with a leading alpha byte) are accepted.
- A `surface`, `text`, or `border` color can be either a single hex string or a two-element array `[light, dark]` for per-appearance colors.
- Button `style` can be `"primary"` or `"secondary"`.
- All properties are optional; anything you omit keeps its default.

<Callout icon="📘" theme="info">
  ### Note

  `IncdTheme.loadJsonTheme(_:)` reads the same JSON to populate both the V1 (`IncdTheme.current`) and V2 (`typography`, `colorPalette`, `displayMode`, `components`) state, so you can theme both systems from one blob.
</Callout>

### UX Configuration via JSON

UX configuration controls layout and chrome for the V2 screens. Pass a JSON string to `IncdUXConfig.loadUXConfig(_:)`.

```swift
let jsonString = """
{
  "showFooter": true,
  "closeButtonPosition": "topLeft",
  "helpButtonPosition": "topRight",
  "headerAlignment": "center",
  "realtimeFeedbackMessageUIFlavor": "standard"
}
"""

IncdUXConfig.loadUXConfig(jsonString)
```

<Accordion title="View available properties and their possible values">
  | Property                          | Type    | Values                               | Default       | Description                                   |
  | --------------------------------- | ------- | ------------------------------------ | ------------- | --------------------------------------------- |
  | `showFooter`                      | Boolean | `true` or `false`                    | `true`        | Controls whether the SDK shows the footer.    |
  | `closeButtonPosition`             | String  | `topRight`, `topLeft`                | `topRight`    | Position of the close button.                 |
  | `helpButtonPosition`              | String  | `topRight`, `topLeft`, `bottomRight` | `bottomRight` | Position of the help button.                  |
  | `realtimeFeedbackMessageUIFlavor` | String  | `standard`, `minimal`                | `standard`    | Visual flavor of real-time feedback messages. |
  | `headerAlignment`                 | String  | `start`, `center`, `end`             | `center`      | Alignment of the header.                      |
</Accordion>

<br />
