React Implementation
The @secure-input/react package provides both a high-level drop-in component and a low-level hook to give you maximum flexibility.
Option 1: The SecureInput Component
The easiest way to get started is using the pre-built <SecureInput /> wrapper. It handles the Web Worker initialization and state management for you automatically.
CouponForm.tsx
import { SecureInput } from "@secure-input/react";
export function CouponForm() {
const handleSubmit = async (encryptedValue: Uint8Array | string) => {
// 1. You receive the encrypted payload
// 2. Send it securely to your backend
const response = await fetch("/api/validate-coupon", {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: encryptedValue,
});
const result = await response.json();
console.log("Coupon valid:", result.valid);
};
return (
<SecureInput
placeholder="Enter your secret coupon code"
onEncryptedSubmit={handleSubmit}
showStatus={true}
className="border-accent"
/>
);
}Component Props
| Prop | Type | Description |
|---|---|---|
onEncryptedSubmit | (encrypted: string) => void | Called on Enter key or internal form submit. Passes the cipher text. |
showStatus | boolean | Optional. Defaults to true. Shows visual indicator of WASM loading state. |
inputProps | React.InputHTMLAttributes | Optional. Standard HTML input attributes to spread onto the internal input field. |
Option 2: The useSecureInput Hook
If you need to build a custom UI (like integrating into a complex form library like React Hook Form), use the useSecureInput hook. This gives you manual control over exactly when encryption happens.
CustomCheckoutForm.tsx
import { useSecureInput } from "@secure-input/react";
import { useState } from "react";
export function CustomCheckoutForm() {
const [plainTextInput, setPlainTextInput] = useState("");
// Initialize the worker hook
const { encrypt, isReady, error } = useSecureInput({
autoInit: true,
debug: false,
});
const handleCheckout = async (e: React.FormEvent) => {
e.preventDefault();
if (!isReady) return;
// Trigger encryption right before network request
const encryptedPayload = await encrypt(plainTextInput);
// Clear the plain text state immediately for safety
setPlainTextInput("");
await fetch("/api/checkout", {
method: "POST",
body: JSON.stringify({ coupon: encryptedPayload })
});
};
return (
<form onSubmit={handleCheckout}>
<input
type="text"
value={plainTextInput}
onChange={(e) => setPlainTextInput(e.target.value)}
disabled={!isReady}
placeholder="Discount code"
/>
<button type="submit" disabled={!isReady}>
Apply & Checkout
</button>
{error && <p className="text-red-500">Encryption failed to load.</p>}
</form>
);
}Best Practice: When using the hook, manually clear your React state (e.g. setPlainTextInput("")) immediately after you have generated the encrypted payload. This minimizes the window of time the plain text exists in memory.