> For the complete documentation index, see [llms.txt](/llms.txt)

# SDK UI Customization Guide

The latest Entrust IDV SDKs for mobile bring an updated design system for the SDKs' UI, which offers new customization options to integrators.

This guide lists the customization options offered via the SDK's [`theme` interface](/sdk/sdk-integration-guide-2025/#user-interface-ui-customization).

> ⚠️ **Warning:** For integration and customization of the Onfido Smart Capture SDKs, including the Onfido Web SDK, please refer to the [Smart Capture SDK language and UI customization
> guide](/sdk/sdk-customization).

## Preface - features not yet available

The SDK UI customization framework will introduce additional capabilities over time, with the following features shortlisted for upcoming releases in 2026:

- Font and text style customization
- Ability to align text and components across the screen
- Ability to set individual left/right/up/bottom padding and border on text and components
- Ability to change default images and icons
- Ability to provide a custom spinner (currently only colors can be modified)

## How to customize the SDK's UI

The SDK UI customization framework described in this guide has expanded its scope compared to its predecessor and introduces the following key features:

- The same UI customization tokens can be used uniformly across all Entrust IDV SDKs (iOS, Android, React Native)
- To simplify integration, UI customization tokens are affecting all related SDK screen elements
- A comprehensive structure is provided to avoid undue duplication of keys and values

  <img src="./color-mapping.png" alt="Example of color mapping" width="500px " />

The framework will be extended to also apply to the Onfido Web and Flutter SDKs later in 2026.

### The `theme` interface

The UI customization framework can be used via the SDK's `theme` configuration interface. This configuration object currently consists of the following major and optional parts:

- `mode`: optionally set to either `Light` or `Dark`. Used to pre-select the SDK UI's theme
- `lightColors` / `darkColors`: centralized color references that can automatically be used across the SDK's screens
- `dimensions`: dimension tokens to customize non-color properties (such as border radii and various sizes)
- `resources.fonts`: configuration object to provide custom fonts to the SDK

  
### Android

    ```kotlin
    override fun onCreate(savedInstanceState: Bundle?) {
      ...
      EntrustIdv.start(
      ...
        configuration = Configuration(
          ...
          theme = Theme(
            ...
            mode = ThemeMode.Light,
            lightColors = mapOf(
              ColorTokens.BackgroundColorBrandDefault to "#FF00FF85",
              ColorTokens.ContentColorBase to "#0B1B0B",
            ),
            darkColors = mapOf(
              ColorTokens.BackgroundColorBrandDefault to "#0000FF85",
              ColorTokens.ContentColorBase to "#FF1CFF",
            ),
            dimensions = mapOf(
              DimensionTokens.ButtonBorderRadius to 8f,
              DimensionTokens.SelectionListItemBorderRadius to 4f,
            ),
            resources = Resources(
              fonts = listOf(
                SdkFont(
                  name = "custom-font",
                  source = listOf(
                    FontSource(
                        location = ResourceLocation.Local(
                          uri = "file:///android_asset/fonts/CustomFont-Regular.ttf" // or "res://font/CustomFont-Regular" (for font files in res/font, no file extension needed in the URI)
                        ),
                        fontFormat = FontFormat.TTF,
                    ),
                  ),
                ),
              )
            )
          )
        )
      )
    }
    ```
  

  
### iOS

    ```swift
      EntrustIdv(
        ...
        configuration: .init(
          ...
          theme: .init(
            ...
            mode: ThemeMode.light,
            lightColors: [
              ColorTokens.backgroundColorBrandDefault: "#FF00FF85",
              ColorTokens.contentColorBase: "#0B1B0B"
            ],
            darkColors: [
              ColorTokens.backgroundColorBrandDefault: "#0000FF85",
              ColorTokens.contentColorBase: "#FF1CFF"
            ],
            dimensions: [
                DimensionTokens.buttonBorderRadius: 8,
            ],
        ))
      )
    ```
  

  
### React Native

    ```javascript
    entrustIdv.start({
      ...
      configuration: {
        ...
        theme: {
          ...
          mode: ThemeMode.Light,
          lightColors: {
            backgroundColorBrandDefault: '#FF00FF85',
            contentColorBase: '#0b1c0b'
          },
          darkColors: {
            backgroundColorBrandDefault: '#0000FF85',
            contentColorBase: '#FF1cFF'
          },
          dimensions: {
            buttonBorderRadius: 8,
            selectionListItemBorderRadius: 4,
          }
        },
      }
    });
    ```
  

Details are provided in the [Entrust IDV SDK integration guide](/sdk/sdk-integration-guide-2025#user-interface-ui-customization).

#### Dimension tokens (`dimensions`)

The `theme` interface exposes a `dimensions` property for customizing non-color tokens. The full list of available tokens is listed in the [Dimension tokens](#dimensions) section.

#### Custom fonts (`resources.fonts`)

The `theme` interface also exposes a `resources.fonts` property to provide custom fonts to the SDK. The full configuration details and list of available font tokens is listed in the [Fonts](#fonts) section.

#### Base color selection and themes (`lightColors` / `darkColors`)

To avoid repeating color override across multiple UI components, the SDK's `lightColors` / `darkColors` interface can be used to configure colors centrally.
By modifying a color value in both colors sets, all component-level tokens derived from them will be affected.
Integrators would then only need to use the component-specific `overrides` for exceptions to standard coloring patterns, such as for extra brand emphasis.

For example, modifying the color set for the `backgroundColorBrandDefault` token in the `lightColors` and `darkColors` will apply that color to all component-specific tokens that are assigned the `backgroundColorBrandDefault` token, such as the background color of the primary button and spinner's main color.
The mapping between the base tokens and component-specific areas is listed in the [Components](#key-components) section below.

The full list of available `lightColors` / `darkColors` tokens is listed in the [Base colors](#base-colors) section below.

> ⚠️ **Warning:** Unless predefined in the SDK's `theme`/`mode` configuration, the UI's theme
> (`Dark` or `Light` mode) is automatically determined by the SDK based on the
> device (or browser) settings. As such, the customization interface is mirrored
> for both themes for `lightColors` and `darkColors`. It is therefore critical
> to **implement default colors for both `lightColors` and `darkColors`** as the
> SDK will make use of both sets of colors across the experience (our capture
> screens are always rendered in dark mode).

# Base colors

Base colors are divided in three categories:

- `contentColor`: affects the 'foreground' color of a component such as its text or icon
- `backgroundColor`: affects the color of the background or surface area of a component
- `borderColor`: affects the color of the outer line of a component

<br />

**Note**:

- Each token can be assigned a color value in `hex` format (e.g. '#FFFFFF' for white). Colors can also be provided as 8-character values to account for transparency (e.g. '#FFFFFF85' for white with 50% opacity/transparency)
- Colors assigned to both `light` and `dark` themes should provide sufficient contrast for accessibility purposes. It is also recommended to provide sufficient differentiation for the `hover` and `active` color variants

If you are migrating from the Onfido Smart Capture SDK, see the [Appendix - UI token mapping](/sdk/sdk-migration-guide-2025/#appendix---ui-token-mapping) in the SDK migration guide for a full mapping of Onfido SDK tokens to these Entrust IDV SDK equivalents.

# General Screen Background, Text & Border

The overall screen background, overlay and border colors can be customized by modifying the base color tokens defined in the table below.

| Base Color Token                         | Description                                                                                               | Light                           | Dark                            |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------- |
| `backgroundColorSurfacePrimaryDefault`   | General background color of the screen                                                                    |    |    |
| `backgroundColorSurfaceSecondaryDefault` | Secondary background color used in media containers                                                       |    |    |
| `backgroundColorOverlay`                 | Color of the semi-transparent overlay visible over live capture screens and when a screen pop-up is shown |  |  |

Additionally, the color of the main text elements can be customized by modifying the following base color tokens:

| Base Color Token                  | Description                                                             | Light                         | Dark                          |
| --------------------------------- | ----------------------------------------------------------------------- | ----------------------------- | ----------------------------- |
| `contentColorBase`                | Color of the body of text and titles                                    |  |  |
| `contentColorSubtle`              | Secondary text color applied to field descriptions and supporting icons |  |  |
| `contentColorNegativeBaseDefault` | Text color used for input validation errors                             |  |  |
| `contentColorPlaceholder`         | Color used for placeholder text within input fields                     |  |  |

**Note**: The color of text or icons within particular components such as buttons or banners is driven by potentially more specific color tokens as defined in the following sections of this guide.

# Key Components

This section presents the components available across the Entrust IDV SDK screens.
If you require customization capabilities beyond the scope described in this document, please contact your Customer Success Manager.

## Buttons

While the behavior of buttons is consistent across screens and platforms, colors are driven by a button's 'variant':

| Variant            | Example                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------- |
| Primary            | <img src="./button-primary.png" alt="Primary Button" width="120px" />                       |
| Secondary          | <img src="./button-secondary.png" alt="Secondary button" width="120px" />                   |
| Tertiary           | <img src="./button-tertiary.png" alt="Tertiary button" width="120px" />                     |
| Negative Secondary | <img src="./button-secondary-negative.png" alt="Secondary-negative button" width="120px" /> |
| Negative Tertiary  | <img src="./button-tertiary-negative.png" alt="Tertiary-negative button" width="120px" />   |

The buttons are currently used in the following parts of the UI:

| Use Case                          | Description                                                                   | Variant                   |
| --------------------------------- | ----------------------------------------------------------------------------- | ------------------------- |
| [Button Dock](#button-dock)       | Call To Action buttons located in most screens                                | `primary` and `secondary` |
| (Web SDK) Cross-device            | Button on the cross-device desktop QR code screen to display more information | `tertiary`                |
| (Web SDK) Cross-device            | Button on the cross-device mobile 'Confirmation' screen for "It's not me"     | `negative-secondary`      |
| (Web SDK) Cross-device            | Button on the cross-device mobile 'Confirmation' screen for "It's not me"     | `negative-tertiary`       |
| [Navigation Bar](#navigation-bar) | Back and Close buttons                                                        | `tertiary`                |
| Intro screens                     | Buttons to control the playback of animation on instruction screens           | `primary`                 |

**Note**: In the current SDK iteration, it is not possible to replace 'transparent' colors

The corner radius of buttons can be customized using the `buttonBorderRadius` [dimension token](#dimension-tokens-dimensions).

<br />

## Button Dock

  <img src="./button-dock.png" alt="Button Dock" width="380px " />

The `button-dock` is the container at the bottom of most screens that contains either one or two buttons.
In addition to customizing the buttons as defined in the section above, the Button Dock has the following customization options:

| Base Color Token                       | Description                                  | Light                         | Dark                          |
| -------------------------------------- | -------------------------------------------- | ----------------------------- | ----------------------------- |
| `backgroundColorSurfacePrimaryDefault` | Surface color behind/around the buttons      |  |  |
| `borderColorSeparator`                 | Color of the upper border of the Button Dock |  |  |

**Note**: The relative position of buttons (stacked or side-by-side) is automatically controlled by the width of the available screen area

## Navigation Bar

  <img src="./nav-bar.png" alt="Navigation Bar" width="380px " />

The `navigation-bar` is the container at the top of screens that may contain the Back and Exit buttons.
In addition to customizing the bottom as defined in the [Buttons](#buttons) section, the Navigation Bar has the following customization options:

| Base Color Token                       | Description                                      | Light                         | Dark                          |
| -------------------------------------- | ------------------------------------------------ | ----------------------------- | ----------------------------- |
| `backgroundColorSurfacePrimaryDefault` | Surface color behind/around the buttons          |  |  |
| `borderColorSeparator`                 | Color of the bottom border of the Navigation Bar |  |  |

## Banner

The `banner` component is used to callout key instructions or live feedback to the user across the UI flow.

| Variant   | Use Case                                                                        |                                                                                               |
| --------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `info`    | User callout on introduction or instruction screens                             |        |
| `warning` | User warning appearing during the capture experience or in confirmation screens |  |
| `error`   | User error appearing during the capture experience or in confirmation screens   |      |

**Notes**:

- The icons currently used within the Banner component cannot be changed
- Capture screens (live camera feeds) are always displayed in dark mode to provide an optimal user experience

The `banner` component is composed of an overall border, a message and an optional icon.

<br />

## Spinner

The `spinner` component is present on all loading and waiting screens of the SDK.

  <img src="./spinner.png" alt="Spinner" width="100px" />

| Base Color Token                      | Description                                    | Light                         | Dark                          |
| ------------------------------------- | ---------------------------------------------- | ----------------------------- | ----------------------------- |
| `backgroundColorBrandDefault`         | Color of the 'progress' section of the spinner |  |  |
| `backgroundColorNeutralSubtleDefault` | Color of the 'track' section of the spinner    |  |  |
| `contentColorSubtle`                  | Color of any possible supporting text          |  |  |

**Note**: On Android, the `spinner` component of the first loading screen (when the SDK is being initialized) only contains a 'progress' section.

## Status Icon Tile

The `icon-tile` component is the large icon present on status screens. It exists in three main variants:

| Use Case            | Description                                                  | Variant    | Example                                                                  |
| ------------------- | ------------------------------------------------------------ | ---------- | ------------------------------------------------------------------------ |
| Confirmation Screen | 'Green tick' when the user has successfully completed a task | `positive` | <img src="./icon-positive.png" alt="Positive Icon" width="50px" />       |
| Permissions Screen  | Icon representing the required permission type               | `neutral`  | <img src="./icon-neutral.png" alt="Neutral Icon" width="50px" />         |
| Error Screen        | 'Red exclamation mark' shown on error screens                | `negative` | <img src="./icon-negative.png" alt="Negative/Error Icon" width="50px" /> |

The icon and background colors can be customized for each variant:

| Variant    | Base Color Token                       | Light                         | Dark                          |
| ---------- | -------------------------------------- | ----------------------------- | ----------------------------- |
| `positive` | `backgroundColorPositiveSubtleDefault` |  |  |
| `positive` | `contentColorPositiveBaseDefault`      |  |  |
| `neutral`  | `backgroundColorNeutralSubtleDefault`  |  |  |
| `neutral`  | `contentColorSubtle`                   |  |  |
| `negative` | `backgroundColorNegativeSubtleDefault` |  |  |
| `negative` | `contentColorNegativeBaseDefault`      |  |  |

## Country Selector

The `country-select` component is present on multiple screens to allow the end user to select a country from a dropdown list or by starting to type in the main input field.
It is also used to select the phone number country prefix.

  <img src="./country-select.png" alt="Country Selection component" width="380px" />

<br />

**Note**: The country flags cannot be edited or replaced.

## Selection List

The `selection-list` component is a custom button list intended to provide end users with multiple choices.

  <img src="./selection-list.png" alt="Selection List" width="380px" />

| Use Case                    | Description                                                                                                     |
| --------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Document Type               | In the context of Document and Proof of Address, presents the user with a list of document types to choose from |
| Cross-Device Link Method    | In the context of cross-device in the Web SDK, selector of the 'link' method available                          |
| Generic user choice screens | Multiple additional use cases for which the user is given a non-hierarchical choice (e.g. eID selection)        |

**Note**: The individual icons present in the list cannot currently be customized

[Android-only currently] The corner radius of selection list items can be customized using the `selectionListItemBorderRadius` [dimension token](#dimension-tokens-dimensions).

## Text Input Field

The `text-input` component is used across any screen or component that requires the user to provide a typed value.

<br />

## Checkbox

The `checkbox` component is a composite element that contains the following sub-components:

- The `container` which corresponds to the overall checkbox, offering the customization of the overall border and background colors
- The checkbox itself. It is referred to by its two main states/variants: `selected` and `unselected`
- The `icon` that corresponds to the 'tick' within the container
- The `label` of the overall component
- The `description` of the overall component

  <img src="./checkbox.png" alt="Checkbox" width="250px" />

The component itself also follows the standard input states of `default`, `active`, `hover`, `disabled` and `invalid`

### Overall `container`

| State    | Base Color Token                       | Light                         | Dark                          |
| -------- | -------------------------------------- | ----------------------------- | ----------------------------- |
| default  | `backgroundColorSurfacePrimaryDefault` |  |  |
| active   | `backgroundColorSurfacePrimaryActive`  |  |  |
| hover    | `backgroundColorSurfacePrimaryHover`   |  |  |
| disabled | `backgroundColorInputDefault`          |  |  |
| invalid  | `backgroundColorInputDefault`          |  |  |
| default  | `borderColorSeparator`                 |  |  |
| active   | `borderColorSeparator`                 |  |  |
| hover    | `borderColorSeparator`                 |  |  |
| disabled | `borderColorSeparator`                 |  |  |
| invalid  | `borderColorSeparator`                 |  |  |

### `selected` and `unselected` Checkbox

| Variant      | State    | Base Color Token                     | Light                         | Dark                          |
| ------------ | -------- | ------------------------------------ | ----------------------------- | ----------------------------- |
| `selected`   | default  | `backgroundColorBrandDefault`        |  |  |
| `selected`   | active   | `backgroundColorBrandActive`         |  |  |
| `selected`   | hover    | `backgroundColorBrandHover`          |  |  |
| `selected`   | disabled | `backgroundColorDisabledDefault`     |  |  |
| `selected`   | invalid  | `backgroundColorNegativeBaseDefault` |  |  |
| `selected`   | default  | `borderColorBrandDefault`            |  |  |
| `selected`   | active   | `borderColorBrandActive`             |  |  |
| `selected`   | hover    | `borderColorBrandHover`              |  |  |
| `selected`   | disabled | `borderColorDisabledDefault`         |  |  |
| `selected`   | invalid  | `borderColorNegativeBaseDefault`     |  |  |
| `unselected` | active   | `backgroundColorInputDefault`        |  |  |
| `unselected` | default  | `backgroundColorInputDefault`        |  |  |
| `unselected` | disabled | `backgroundColorInputDefault`        |  |  |
| `unselected` | hover    | `backgroundColorInputDefault`        |  |  |
| `unselected` | invalid  | `backgroundColorInputDefault`        |  |  |
| `unselected` | default  | `borderColorInputDefault`            |  |  |
| `unselected` | active   | `borderColorInputActive`             |  |  |
| `unselected` | hover    | `borderColorInputHover`              |  |  |
| `unselected` | disabled | `borderColorDisabledDefault`         |  |  |
| `unselected` | invalid  | `borderColorNegativeBaseDefault`     |  |  |

### `icon` sub-component

| State    | Base Color Token              | Light                         | Dark                          |
| -------- | ----------------------------- | ----------------------------- | ----------------------------- |
| default  | `contentColorBrandOnBrand`    |  |  |
| active   | `contentColorBrandOnBrand`    |  |  |
| hover    | `contentColorBrandOnBrand`    |  |  |
| invalid  | `contentColorBrandOnBrand`    |  |  |
| disabled | `contentColorDisabledDefault` |  |  |

### `label` sub-component

| State    | Base Color Token              | Light                         | Dark                          |
| -------- | ----------------------------- | ----------------------------- | ----------------------------- |
| default  | `contentColorSubtle`          |  |  |
| disabled | `contentColorDisabledDefault` |  |  |

### `description` sub-component

| State    | Base Color Token              | Light                         | Dark                          |
| -------- | ----------------------------- | ----------------------------- | ----------------------------- |
| default  | `contentColorBase`            |  |  |
| disabled | `contentColorDisabledDefault` |  |  |

# Dimensions

The following dimension tokens are currently supported:

| Token | Description |
|---|---|
| `buttonBorderRadius` | Corner radius applied to all primary and secondary buttons (`dp` / `pt`) |
| `selectionListItemBorderRadius` | Corner radius for selection-list items such as the document type picker (`dp` / `pt`). Currently only available for Android and React Native |

Values are expressed as density-independent pixels (`dp` on Android, points in `pt` on iOS). Accepted values: non-negative numbers.

**Please note**: Dimensions are currently only available for native Android and iOS modules. The same functionality will be added for Web modules in an upcoming release.

  
### Android

    ```kotlin
    EntrustIdv.start(
      configuration = Configuration(
        theme = Theme(
          dimensions = mapOf(
            DimensionTokens.ButtonBorderRadius to 8f,
            DimensionTokens.SelectionListItemBorderRadius to 4f,
          ),
        )
      )
    )
    ```
  

  
### iOS

    ```swift
    EntrustIdv(
      configuration: .init(
        theme: .init(
          dimensions: [
            DimensionTokens.buttonBorderRadius: 8,
          ]
        )
      )
    )
    ```
  

  
### React Native

    ```javascript
        entrustIdv.start({
          configuration: {
            theme: {
              dimensions: {
                buttonBorderRadius: 8,
                selectionListItemBorderRadius: 4,
              },
            },
          }
        });
        ```
  

# Fonts

The SDK supports the use of custom fonts via the `resources.fonts` property of the `Theme` object. Custom fonts are applied across all SDK screens.

Each font is defined by a **name** (used for internal identification) and one or more **sources** — a list of font locations with their corresponding format. The SDK will attempt each source in order and use the **first** one it can successfully load, allowing fallback support across source types and formats.

**Supported formats**

| Format | Android | iOS | React Native / Web |
|--------|---------|-----|--------------------|
| `ttf` (TrueType) | ✔ | ✔ | ✔ |
| `otf` (OpenType) | API 26+ | ✔ | ✔ |
| `woff2` | — | — | ✔ (web modules only) |

**Font source types**

Two source types are available via `ResourceLocation`:

| Type | Description |
|------|-------------|
| `remote` | Font is downloaded at runtime from a publicly accessible URL |
| `local` | Font is bundled in the host app — URI is the filename as registered in the app bundle (without extension) |

---

## Local fonts

Local fonts are bundled directly in the host app. The font file must be included in the host app bundle ahead of SDK initialization. The `uri` format differs per platform — see the platform-specific instructions below.

> ℹ️ **Note:** Local font support is available on Android from version 100.4.0 and on iOS from version 100.8.0.

  
### Android

    Your font file can be placed in either of the following locations in your app bundle:
    - `assets/` folder, then referenced by filename using a `file:///android_asset/` URI
    - `res/font/` folder, then referenced by font name without the file extension (NOT filename) using a `res://font/` URI

    ```kotlin
    EntrustIdv.start(
      configuration = Configuration(
        theme = Theme(
          resources = Resources(
            fonts = listOf(
              SdkFont(
                name = "custom-font",
                source = listOf(
                  FontSource(
                    location = ResourceLocation.Local(
                      uri = "file:///android_asset/fonts/CustomFont-Regular.ttf"
                    ),
                    fontFormat = FontFormat.TTF,
                  ),
                ),
              ),
              SdkFont(
                name = "custom-font-fallback",
                source = listOf(
                  FontSource(
                    location = ResourceLocation.Local(
                      uri = "res://font/CustomFont-Regular-Fallback" // no file extension needed for fonts in res/font
                    ),
                    fontFormat = FontFormat.TTF,
                  ),
                ),
              ),
            )
          )
        )
      )
    )
    ```

    Variable fonts are also supported (on devices with Android 8.0+). XML font family resources are not currently supported.
  

  
### iOS

    Add the font file to your Xcode project. Make sure:
    - **Copy items if needed** is checked
    - Your **app target** is checked under "Add to targets"

    Register it in your `Info.plist` under **Fonts provided by application**:

    ```xml
    <key>UIAppFonts</key>
    <array>
      <string>YourFont-Regular.otf</string>
    </array>
    ```

    > ℹ️ **Note:** The font family name can differ from the filename. To find the correct name to pass to the SDK, you can either:
> 1. Open the font in **Font Book** → look under "PostScript Name"
> 2. Or programmatically after registering the font in `Info.plist`:
> ```swift
> for family in UIFont.familyNames.sorted() {
> for name in UIFont.fontNames(forFamilyName: family) {
> print(name)
> }
> }
> ```

    Then pass it to the SDK via `Configuration`:

    ```swift
    let fontURL = Bundle.main.url(forResource: "YourFont-Regular", withExtension: "otf")

    let font = SdkFont(
      name: "YourFontPostScriptName",
      source: [
        FontSource(
          location: .local(uri: fontURL?.absoluteString ?? ""),
          fontFormat: .otf
        )
      ]
    )

    EntrustIdv(
      sdkParameters: StudioParameters(
        sdkToken: "your-sdk-token",
        configuration: Configuration(
          theme: Theme(
            resources: Resources(fonts: [font])
          )
        )
      ),
      callbacks: callbacks
    )
    ```
  

  
### React Native

    A local font file must be bundled **natively per-platform** by the integrator — the JS
    bundle cannot transport font bytes, so the file must be placed in each native project
    ahead of SDK initialization:

    - **Android**: place the font file under `android/app/src/main/assets/` in the host app.
    - **iOS**: add the font file as an Xcode bundle resource **and** declare it in the host
      app's `Info.plist` under `UIAppFonts` (required for native `UIFont` lookups to resolve
      the custom family name).

    > ℹ️ **Note:** `woff2` is not supported for native modules. Use `ttf` or `otf` for local fonts on
> React Native.

    > ⚠️ **Warning:** Only the first `SdkFont` in the `fonts` array is applied — unlike Android/iOS native,
> there is no fallback to a subsequent font if the first fails to load. Similarly, only
> the first `FontSource` within that font's `source` list is used; it is not
> attempted-in-order with fallback on failure as it is in Android/iOS.

    Once the font file is bundled natively as described above, use the exported
    `resolveLocalFont` helper in JS to build the platform-correct `FontSource` from the
    filename — it resolves the native URI via the `RNEntrustIDV.resolveLocalFontUri` bridge
    method, so your JS code stays platform-agnostic. `resolveLocalFont` only looks up a file
    that has already been bundled; it does not perform the bundling itself.

    ```ts
    import { resolveLocalFont, FontFormat } from '@entrust.corporation/idvsdk-reactnative';

    const fontSource = resolveLocalFont('CustomFont-Regular.ttf', FontFormat.TTF);
    // fontSource is undefined if the file isn't found in the native bundle for the current platform
    ```

    > ⚠️ **Warning:** `resolveLocalFont` can return `undefined` if the file isn't found natively for the
> current platform. Check for this and omit the font entry entirely rather than passing
> an empty `source` array — a font with no sources is silently skipped by the SDK, which
> can mask the real problem (the file missing from the native bundle).

    ```ts
    const fontSource = resolveLocalFont('CustomFont-Regular.ttf', FontFormat.TTF);

    const parameters: SdkParameters = {
      sdkToken: 'your-sdk-token',
      configuration: {
        theme: {
          resources: {
            icons: {},
            images: {},
            videos: {},
            animations: {},
            fonts: fontSource ? [fontSource] : [],
          },
        },
      },
    };

    idv.start(parameters);
    ```

    > ⚠️ **Warning:** On iOS, `name` must match the font's PostScript name, not the filename. Open the font
> file in **Font Book** → "PostScript Name" to find it. A mismatch will cause the SDK to
> fall back to the system font silently.
  

---

## Remote fonts

Remote fonts are downloaded by the SDK at runtime from a publicly accessible URL and cached to disk after the first download — subsequent SDK launches use the cached version without a network request.

  
### Android

    The `uri` must be a publicly accessible HTTPS URL pointing directly to a `.ttf` or `.otf` file.

    > ℹ️ **Note:** `woff2` is not supported for native modules. Use `ttf` or `otf` for remote fonts on Android.
> `otf` requires API 26+.

    ```kotlin
    EntrustIdv.start(
      configuration = Configuration(
        theme = Theme(
          resources = Resources(
            fonts = listOf(
              SdkFont(
                name = "custom-font",
                source = listOf(
                  FontSource(
                    location = ResourceLocation.Remote(
                      uri = "https://example.com/fonts/CustomFont-Regular.ttf"
                    ),
                    fontFormat = FontFormat.TTF,
                  ),
                  FontSource(
                    location = ResourceLocation.Remote(
                      uri = "https://fallback.example.com/fonts/CustomFont-Regular.otf"
                    ),
                    fontFormat = FontFormat.OTF,
                  ),
                ),
              ),
            )
          )
        )
      )
    )
    ```

    > ℹ️ **Note:** If a local font source appears **before** a remote source in the list, the remote font
> will not be downloaded — the local font will be used instead. The remote source is only
> attempted if all preceding sources fail to load (e.g. an OTF local font on API &lt; 26).

    > ℹ️ **Note:** Remote fonts require an active internet connection on first launch. Downloads that exceed
> 15 seconds or 20 MB are aborted and the next source is attempted. If all sources fail,
> the SDK falls back to the system font and continues normally.
  

  
### iOS

    The `uri` must be a publicly accessible HTTPS URL pointing directly to a `.ttf` or `.otf` file.

    > ℹ️ **Note:** `woff2` is not supported for native modules. Use `ttf` or `otf` for remote fonts on iOS.

    Multiple sources can be provided — the SDK will attempt each in order and use the **first**
    one that successfully downloads and registers. This allows fallback URLs in case the primary
    source is unavailable.

    ```swift
    let font = SdkFont(
      name: "YourFontPostScriptName",
      source: [
        FontSource(
          location: .remote(uri: "https://example.com/fonts/YourFont-Regular.ttf"),
          fontFormat: .ttf
        ),
        FontSource(
          location: .remote(uri: "https://fallback.example.com/fonts/YourFont-Regular.otf"),
          fontFormat: .otf
        )
      ]
    )

    EntrustIdv(
      sdkParameters: StudioParameters(
        sdkToken: "your-sdk-token",
        configuration: Configuration(
          theme: Theme(
            resources: Resources(fonts: [font])
          )
        )
      ),
      callbacks: callbacks
    )
    ```

    > ⚠️ **Warning:** The `name` field must match the font's PostScript name, not the filename.
> To find the PostScript name, open the font in **Font Book** → look under "PostScript Name".
> A mismatch will cause the SDK to fall back to the system font silently.

    > ℹ️ **Note:** Remote fonts require an active internet connection on first launch. If all sources fail
> to download, the SDK falls back to the system font and continues normally.
  

  
### React Native

    The `uri` must be a publicly accessible HTTPS URL pointing directly to a `.ttf` or `.otf` file.

    > ℹ️ **Note:** `woff2` is not supported for native modules. Use `ttf` or `otf` for remote fonts on React Native.

    > ℹ️ **Note:** Remote font support on React Native is available from version 100.8.0.

    > ⚠️ **Warning:** The `resources` object currently requires all five keys (`icons`, `images`, `videos`,
> `animations`, `fonts`) to be present, even if only `fonts` is used — pass empty objects
> for the rest. Omitting a key will cause the SDK to fail to start. This requirement will
> be relaxed in a future release.

    ```ts
    import { EntrustIdv, ResourceLocationType, FontFormat } from '@entrust.corporation/idvsdk-reactnative';
    import type { SdkParameters } from '@entrust.corporation/idvsdk-reactnative/capture-api/SdkParameters';

    const parameters: SdkParameters = {
      sdkToken: 'your-sdk-token',
      configuration: {
        theme: {
          resources: {
            icons: {},
            images: {},
            videos: {},
            animations: {},
            fonts: [
              {
                name: 'YourFontPostScriptName',
                source: [
                  {
                    location: {
                      type: ResourceLocationType.Remote,
                      uri: 'https://example.com/fonts/YourFont-Regular.ttf',
                    },
                    fontFormat: FontFormat.TTF,
                  },
                ],
              },
            ],
          },
        },
      },
    };

    idv.start(parameters);
    ```

    > ⚠️ **Warning:** On iOS, `name` must match the font's PostScript name, not the filename — this applies
> to React Native too, since it bridges to the native iOS SDK. To find the PostScript name,
> open the font in **Font Book** → look under "PostScript Name". A mismatch will cause the
> SDK to fall back to the system font silently.

    > ℹ️ **Note:** Remote fonts require an active internet connection on first launch. If all sources fail
> to download, the SDK falls back to the system font and continues normally.
  

---

## Multiple sources and fallbacks

Multiple `FontSource` entries can be provided per font. The SDK will attempt each source in declared order and use the **first** one it can successfully load. This enables:

- **Format fallbacks** — supply both TTF and OTF variants for broader device compatibility
- **URL fallbacks** — supply a backup remote URL in case the primary is unavailable
- **Mixed fallbacks** — combine remote and local sources so a bundled font is used if the remote download fails

```kotlin
SdkFont(
  name = "custom-font",
  source = listOf(
    FontSource(
      location = ResourceLocation.Remote(uri = "https://example.com/fonts/CustomFont.ttf"),
      fontFormat = FontFormat.TTF
    ),
    FontSource(
      location = ResourceLocation.Local(uri = "file:///android_asset/fonts/FallbackFont.ttf"),
      fontFormat = FontFormat.TTF
    ),
  )
)
```

Multiple fonts can be provided in the `fonts` array — for example a primary and a fallback font. The SDK resolves the **first font** in the array that can be successfully loaded.