For the complete documentation index, see llms.txt. This page is also available as Markdown.

UI Customization

The web components have extensive theming and customization capabilities, you can fine tune all the colors and tweak most of the relevant CSS styles of every element, and if that’s not enough you can completely replace the single elements through slots, making the components truly 100% customizable.

The theme can be customized through the theme-options or themeOptions attribute, it accepts an object with the following structure:

interface ThemeOptions {
  colors: {
    dark: {
      primary: string;
      onPrimary: string;
      secondary: string;
      onSecondary: string;
      error: string;
      onError: string;
      secondaryContainer: string;
      onSecondaryContainer: string;
      surface: string;
      onSurface: string;
      surfaceVariant: string;
      onSurfaceVariant: string;
    };
    light: {
      primary: string;
      onPrimary: string;
      secondary: string;
      onSecondary: string;
      error: string;
      onError: string;
      secondaryContainer: string;
      onSecondaryContainer: string;
      surface: string;
      onSurface: string;
      surfaceVariant: string;
      onSurfaceVariant: string;
    };
  };
  elements: {
    button: {
      host: {
        borderRadius: string;
        fontSize: string;
        fontWeight: string;
        padding: string;
      };
      size: {
        small: {
          host: {
            fontSize: string;
            padding: string;
          };
        };
      };
      variant: {
        text: {
          host: {
            borderBottom: string;
            hover: {
              opacity: string;
            };
          };
        };
      };
    };
    camera: {
      host: {
        after: {
          background: string;
          height: string;
        };
        before: {
          background: string;
          height: string;
        };
      };
    };
    cameraCorners: {
      svg: {
        strokeWidth: string;
      };
    };
    cameraInstructions: {
      host: {
        gap: string;
      };
      li: {
        borderRadius: string;
        gap: string;
        padding: string;
      };
      liText: {
        fontSize: string;
      };
    };
    cameraSelect: {
      labels: {
        gap: string;
        padding: string;
      };
      labelsHeadline: {
        fontSize: string;
        fontWeight: string;
      };
      labelsText: {
        fontSize: string;
        fontWeight: string;
      };
      list: {
        borderRadius: string;
        margin: string;
        padding: string;
        top: string;
      };
      option: {
        borderRadius: string;
        marginTop: string;
        padding: string;
      };
    };
    dialog: {
      host: {
        border: string;
        borderRadius: string;
        boxShadow: string;
      };
    };
    poweredBy: {
      host: {
        gap: string;
        height: string;
      };
      icon: {
        height: string;
        width: string;
      };
      span: {
        fontSize: string;
        fontWeight: string;
        letterSpacing: string;
      };
    };
    qrcode: {
      host: {
        borderRadius: string;
        padding: string;
      };
    };
    root: {
      buttonCameraSelect: {
        right: string;
        top: string;
      };
      buttonCancel: {
        left: string;
        top: string;
      };
      buttonClose: {
        left: string;
        top: string;
      };
      buttonFlash: {
        right: string;
        top: string;
      };
      buttonPin: {
        height: string;
        width: string;
      };
      buttonsSwitchToMobileChoice: {
        gap: string;
      };
      cameraBiometric: {
        width: string;
      };
      cameraTip: {
        backdropFilter: string;
        borderRadius: string;
        fontSize: string;
        fontWeight: string;
        height: string;
        padding: string;
        top: string;
      };
      headline: {
        fontSize: string;
        fontWeight: string;
        marginTop: string;
      };
      host: {
        borderRadius: string;
        gap: string;
        padding: string;
      };
      poweredBy: {
        bottom: string;
      };
      text: {
        fontSize: string;
        fontWeight: string;
      };
      texts: {
        gap: string;
      };
    };
  };
}

Let’s quickly explain how this interface is structured, the two main blocks are colors and elements, as for colors it is quite simple to grasp, two palettes are exposed which are dark and light, making the components able to support dark and light themes.

To better understand the semantics behind the name of the colors please refer to this illustration:

Regarding the elements block it grants you the capability of changing the styles of all elements, the names are quite straightforward with just one exception: root, this name is a codename that we reserve for the abstraction layer behind the Auth and Enroll elements.

The host key in each element block refers to the root of that element, meaning that the style is applied directly to the target element.

The other names are quite easy to associate to each element on screen, if unsure please try to tweak the values and test if the expected style change was applied, otherwise please ask Keyless for further info.

Finally, here’s the default values that Keyless uses:

Here’s an example of changing the primary and surface colors:

Slots

The slot element is a powerful tool that allows extensive customization in cases like the usage of this package, please refer to the MDN Web Docs to read more about this technology.

The kl-auth, kl-auth-dialog, kl-enroll and kl-enroll-dialog web components support the following slots:

Slot

Description

button-cancel

The circle button with the left arrow icon on the top left of the component, its action is reconnecting to the WebSocket and restarting the whole flow from zero.

button-close

The circle button with the x icon on the top right of the component, its action is closing the WebSocket connection and emitting the close event used by the dialog components to close the dialog.

spinner

The spinner animation.

icon-done

The checkmark animation.

icon-error

The error animation.

face-scan

The animation that shows when the server is enrolling a user after the frame acquisition.

texts

The title and description block.

camera-instructions

The list of camera instructions that the user should follow to perform a successful authentication or enrollment.

button-camera-permission

The button that checks and potentially requests the camera permission to the user.

camera-tip

The text tip on the top of the component when the cameras are on that suggests to the user how to better frame themself, only shown if camera checks are enabled.

camera-select

The select that is shown when the user is on a desktop device and has multiple cameras, grants the user the capability of picking a different camera than the default one.

button-flash

The circle button with the flash icon on the top right of the component, its action is to force a white background on the screen.

button-camera-select-button

The circle button with the camera icon on the top right of the component, its action redirects the user to the camera selection screen.

camera-biometric

The main camera stream, useful for the user to adjust their camera quality in realtime.

camera-corners

The corners that serve as a reference for the user to position their face, they also indicate whether the quality filters are positive or negative.

buttons-stm-choice

The switch to mobile buttons, the primary button leads to a qrcode that lets the user continue the flow on their phone. The secondary button lets the user continue the flow on their current device.

stm-qrcode

The qrcode that allows the user to continue the flow on their phone.

button-retry

The retry button, reconnects to the WebSocket and restarts the whole flow from zero.

powered-by

The powered by Keyless element, always visible when enabled at the bottom of the component.

Let’s look at a few examples on how to use the slots, for example how to change the spinner:

Another example that shows how the visibility logic of the retry button could be customized, for example showing the retry button only when the liveness fails:

Last updated

Was this helpful?