Styling the KYC SDK
Three ways to restyle the embedded KYC flow, why overriding from your own stylesheet needs care, and every CSS class and theme variable the SDK supports.
There are three ways to change how the SDK looks. Use the highest one that does the job, because each is more coupled to SDK internals than the one above it.
| # | Route | Where it lives | Use it for |
|---|---|---|---|
| 1 | Theme configuration | Admin panel, or the theme config object | Colours, fonts, spacing. No CSS at all. |
| 2 | customCSS | Provider config at init | Anything the theme does not expose. Always wins inside the SDK. |
| 3 | Your own stylesheet | Your app's CSS | When the CSS must live in your codebase. Read the rules below first. |
How the SDK's CSS reaches the page
There is no Shadow DOM, so every element is reachable from your stylesheet. On mount the SDK appends
three <style> elements to <head>, in this order.
| Element id | Contents |
|---|---|
metakyc-sdk-styles | The component stylesheet, scoped under .metakyc-sdk. |
metakyc-theme-vars | The --metakyc-* variables for the resolved theme. |
metakyc-custom-css | Your customCSS, appended last so it wins. |
Two things make route 3 harder than it looks
Every theme variable is emitted with !important, and these style elements are appended at runtime,
so they sit after your build-time stylesheet in <head>. A rule of equal specificity loses on document
order. To win from your own CSS you need !important and a selector more specific than
.metakyc-sdk.
What does not work
| Attempt | Why it fails |
|---|---|
:root { --metakyc-primary: ... } | The variable is declared directly on the .metakyc-sdk element, and a direct declaration always beats an inherited one. |
.metakyc-sdk { ... !important } | Ties on specificity, then loses on document order because the SDK's style element is appended later. |
Any rule without !important | Loses to the !important on the SDK's own declaration. |
The first of those is the one to watch: :root is what most people reach for, and it fails silently.
The pattern that works
Pass your own class through className. It lands on the same element as .metakyc-sdk, so
.my-kyc.metakyc-sdk is strictly more specific and wins regardless of injection order.
<MetaKYC className="my-kyc" />/* Your stylesheet. Override the VARIABLES, not the properties. */
.my-kyc.metakyc-sdk,
.metakyc-searchable-select-dropdown,
.metakyc-multiselect-dropdown {
--metakyc-primary: #5046D5 !important;
--metakyc-input-bg: #ffffff !important;
--metakyc-input-border: #d1d5db !important;
--metakyc-font-family: 'Inter Tight', sans-serif !important;
}Override variables, not properties
The SDK's component rules are !important, but their values read var(--metakyc-*). Winning the
variable therefore reaches every rule that uses it. Beating a property directly means out-specifying
selectors such as .metakyc-sdk input:not([type="checkbox"])..., which is far more work for the same
result.
Dropdowns render outside the shell
The searchable select and multi-select dropdowns are portalled to document.body, so they are not
inside .metakyc-sdk. Repeat your variable block on .metakyc-searchable-select-dropdown and
.metakyc-multiselect-dropdown, or those two controls keep the old palette.
Theme variables
Every variable below is settable, and every variable the stylesheet reads is in this list. Names are
prefixed --metakyc-.
| Group | Variables |
|---|---|
| Brand | primary, primary-hover, primary-light, primary-dark, secondary, secondary-hover |
| Status | success, warning, danger, info |
| Status backgrounds | success-bg, warning-bg, danger-bg, info-bg |
| Surfaces | background, surface, border |
| Text | text-primary, text-secondary, text-muted |
| Inputs | input-bg, input-text, input-border, input-border-focus, input-placeholder |
| Header and footer | header-bg, header-text, footer-bg, footer-text |
| Typography | font-family, heading-font, font-size-*, font-weight-* (one per key in your theme) |
| Spacing | One variable per key in the theme's spacing object, kebab-cased |
CSS classes
These are the supported styling hooks. Treat anything not listed here, and every Tailwind utility class in the markup, as internal and liable to change.
Shell and layout
| Class | Element |
|---|---|
metakyc-sdk | The root shell wrapping everything. Your className is appended here. |
metakyc-vertical-layout | Vertical (stepper beside content) layout container. |
metakyc-form-grid | Grid that lays out form fields. |
metakyc-header | Header bar. |
metakyc-header-title | Title text in the header. |
metakyc-logo | Tenant logo. |
metakyc-paragraph | Body copy block rendered from configuration. |
Card
| Class | Element |
|---|---|
metakyc-card-header | Card header region. |
metakyc-card-content | Card body region. |
metakyc-card-footer | Card footer region, usually the action buttons. |
Stepper and progress
| Class | Element |
|---|---|
metakyc-progress-wrapper | Wrapper around the whole progress indicator. |
metakyc-stepper-scroll | Scrollable strip holding the steps. |
metakyc-step-icon | Per-step icon or number badge. |
metakyc-step-label | Per-step label. |
metakyc-step-label--current | Added to the label of the active step. |
metakyc-step-title | Title of the step being rendered. |
metakyc-step-description | Description under the step title. |
metakyc-step-content | The active step's content area. |
metakyc-step-connector | Connector line drawn between steps. |
metakyc-overview-step-item | One row in the overview (summary) step. |
Fields and options
| Class | Element |
|---|---|
metakyc-field-label | Label above a form field. |
metakyc-input-label | Label bound to a text input. |
metakyc-options-group | Group wrapping radio or checkbox options. |
metakyc-option-input | The radio or checkbox control itself. |
metakyc-option-label | Clickable label around one option. |
metakyc-option-text | Text of one option. |
metakyc-link-field | Field rendered as a link, for example a consent document. |
metakyc-help-btn | The inline help button next to a field. |
Searchable select
| Class | Element |
|---|---|
metakyc-searchable-select-trigger | The closed control you click to open it. |
metakyc-searchable-select-dropdown | The open panel. Portalled outside the shell. |
metakyc-searchable-select-option | One option row. |
metakyc-searchable-select-search | The search input inside the panel. |
Multi-select
| Class | Element |
|---|---|
metakyc-multiselect | Wrapper around the control. |
metakyc-multiselect-trigger | The closed control. |
metakyc-multiselect-dropdown | The open panel. Portalled outside the shell. |
metakyc-multiselect-option | One option row. |
metakyc-multiselect-search | The search input inside the panel. |
metakyc-multiselect-placeholder | Placeholder shown when nothing is selected. |
metakyc-multiselect-arrow | The open and close chevron. |
metakyc-multiselect-chip | One selected value, shown as a chip. |
metakyc-multiselect-chip-remove | The remove control on a chip. |
File upload and cascading tree
| Class | Element |
|---|---|
metakyc-file-upload | The upload control as a whole. |
metakyc-file-dropzone | The drag and drop target. |
metakyc-file-item | One uploaded file row. |
metakyc-cascading-tree | Wrapper for a cascading (parent and child) selector. |
metakyc-cascading-tree-levels | The container holding its levels. |
Prefer the theme first
If a colour or font is all you need, set it in the admin panel or the theme object and skip CSS
entirely. Pin it with configVersion (see KYC integration) so a later change
to the live configuration cannot move your UI unexpectedly.
KYC webhooks
The authoritative KYC result channel. The common envelope, every event type MetaKYC emits, sample payloads, and how to register a subscription.
Off-chain sale (bank transfer)
Create a bank-transfer primary-sale purchase, show the returned payment instruction, and track reconciliation and delivery.