Skip to main content

React integration: getting started

This guide covers integrating Weavr Web SDK UI components with React 18+ using functional components and hooks. You learn the correct patterns for script loading, lifecycle management, and the four distinct component integration patterns.

Overview and quick start

Prerequisites

  • React 18.x or later with functional components
  • A Weavr account with an active UI key
  • Basic understanding of React hooks (useEffect, useRef, useState)

5-minute minimal example

This simple example shows our password input component working in a React app.

1. Add the SDK to your index.html

<!doctype html>
<html>
<head>
<script src="https://sandbox.weavr.io/app/secure/static/client.1.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>

2. Create a password input component

Create a new React component for each Weavr web component you want to use in your app. This component manages the rendering and state of the Web SDK component.

import React, { useEffect, useRef, useState } from "react";

const PasswordInput: React.FC = () => {
const containerRef = useRef<HTMLDivElement>(null);
const formRef = useRef<any>(null);

useEffect(() => {
if (!window.OpcUxSecureClient) {
console.error("Weavr SDK not loaded - check index.html script tag");
return;
}

window.OpcUxSecureClient.init(import.meta.env.VITE_WEAVR_UI_KEY);

const form = window.OpcUxSecureClient.form();
const input = form.input("password", "password", {
placeholder: "Enter password",
});

formRef.current = form;
input.mount(containerRef.current);

// Cleanup on unmount
return () => {
try {
form.destroy();
} catch (e) {
console.warn("Error destroying form:", e);
}
};
}, []);

const handleSubmit = () => {
formRef.current?.tokenize(
(tokens: Record<string, string>) => {
console.log("Password token:", tokens.password);
// Send tokens.password to your server
},
(error: any) => {
console.error("Tokenize failed:", error);
}
);
};

return (
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
>
<div id="password-container" ref={containerRef}></div>
<button type="submit">Submit</button>
</form>
);
};

export default PasswordInput;

Script loading

Critical requirement

The Weavr SDK must be loaded via a <script> tag in index.html. Do not import it through Vite, webpack, or any bundler.

See Framework Integration Overview for details on why this is required.

Vite configuration

Add the SDK to index.html in your project root:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Your App</title>

<!-- Weavr SDK - MUST be loaded here, not via import -->
<script src="https://sandbox.weavr.io/app/secure/static/client.1.js"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

Create React App configuration (legacy)

caution

Create React App is no longer maintained. For new projects, use Vite or a meta-framework such as Next.js or Remix.

For existing CRA projects, add the SDK to public/index.html:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>

<!-- Weavr SDK -->
<script src="https://sandbox.weavr.io/app/secure/static/client.1.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>

In CRA projects, initialize the SDK using process.env.REACT_APP_WEAVR_UI_KEY instead of import.meta.env.VITE_WEAVR_UI_KEY.

Environment-based SDK URLs

For production deployments, use different SDK URLs per environment:

<script>
// Determine SDK URL based on environment
const sdkUrl =
window.location.hostname === "localhost"
? "https://sandbox.weavr.io/app/secure/static/client.1.js"
: "https://secure.weavr.io/app/secure/static/client.1.js";

const script = document.createElement("script");
script.src = sdkUrl;
document.head.appendChild(script);
</script>

Or use separate HTML files for each environment.

SDK initialization

Initialize the SDK once when your app starts (Vite example):

// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

// Type declarations for the SDK
declare global {
interface Window {
OpcUxSecureClient: {
init: (
uiKey: string,
options?: { fonts?: Array<{ cssSrc: string }> }
) => void;
form: () => WeavrForm;
span: (type: string, token: string, options?: object) => WeavrSpan;
associate: (
token: string,
onSuccess: () => void,
onError?: (e: Error) => void
) => void;
consumer_kyc: () => {
init: (config: {
selector: string;
reference: string;
lang?: string;
onMessage?: (message: string, additionalInfo?: any) => void;
onError?: (error: string) => void;
}) => void;
};
kyb: () => {
init: (
selector: string,
auth: { reference: string },
listener: (messageType: string, payload: any) => void,
options?: { lang?: string }
) => void;
};
kyc: () => {
init: (
selector: string,
auth: { reference: string },
listener: (messageType: string, payload: any) => void,
options?: { lang?: string }
) => void;
};
};
}
}

interface WeavrForm {
input: (name: string, field: string, options?: object) => WeavrInput;
tokenize: (
resolve?: (tokens: Record<string, string>) => void,
reject?: (error: any) => void
) => void;
destroy: () => void;
}

interface WeavrInput {
mount: (element: HTMLElement | string) => void;
unmount: () => void;
destroy: () => void;
on: (event: string, callback: (data: unknown) => void) => void;
}

interface WeavrSpan {
mount: (element: HTMLElement | string) => void;
unmount: () => void;
on: (event: string, callback: (data: unknown) => void) => void;
}

// Initialize SDK
const initializeSDK = () => {
if (!window.OpcUxSecureClient) {
console.error("Weavr SDK not loaded");
return;
}

window.OpcUxSecureClient.init(import.meta.env.VITE_WEAVR_UI_KEY, {
fonts: [
{
cssSrc: "https://fonts.googleapis.com/css?family=Inter:400,500,600",
},
],
});
};

initializeSDK();

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

Per-component initialization

For simpler setups, initialize in each component:

import React, { useEffect } from "react";

const MyComponent: React.FC = () => {
useEffect(() => {
if (window.OpcUxSecureClient) {
window.OpcUxSecureClient.init("your_ui_key");
}
}, []);

return <div>...</div>;
};
caution

Calling init() multiple times is safe, but wasteful. Prefer app-level initialization for larger apps.

Next steps