React Quick Start
Get running with encrypted state in 5 minutes.
Install
npm install @p47h/vault-react
1. Add the Provider
The provider initializes and owns the Vault lifecycle. It loads the WASM core, manages authentication state, and exposes a consistent Vault instance to the component tree.
// main.tsx
import { P47hProvider } from "@p47h/vault-react";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<P47hProvider>
<App />
</P47hProvider>
);
The provider is a singleton. Mount it once at the root.
2. Handle Identity
Use useIdentity to manage registration, login, and logout without leaking keys or managing crypto state manually.
import { useIdentity } from "@p47h/vault-react";
function AuthForm() {
const { register, login, logout, isAuthenticated, isLoading } = useIdentity();
if (isLoading) return <p>Loading...</p>;
if (isAuthenticated) {
return <button onClick={logout}>Lock Vault</button>;
}
return (
<form onSubmit={(e) => {
e.preventDefault();
const password = e.target.password.value;
login(password);
}}>
<input name="password" type="password" />
<button type="submit">Unlock</button>
</form>
);
}
3. Use Encrypted State
Secrets behave like React state. They load automatically when the vault unlocks and become unavailable when it locks.
import { useSecret } from "@p47h/vault-react";
function ApiKeyManager() {
const [apiKey, setApiKey, { isLoading, error }] = useSecret("stripe_key");
if (isLoading) return <p>Decrypting...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<input
value={apiKey ?? ""}
onChange={(e) => setApiKey(e.target.value)}
placeholder="sk_live_..."
/>
</div>
);
}
When setApiKey is called, the value is encrypted and persisted to IndexedDB. The plaintext never touches localStorage or sessionStorage.
Complete Example
import { P47hProvider, useIdentity, useSecret } from "@p47h/vault-react";
function App() {
const { isAuthenticated } = useIdentity();
return (
<div>
<AuthForm />
{isAuthenticated && <SecretEditor />}
</div>
);
}
function SecretEditor() {
const [token, setToken] = useSecret("github_token");
return (
<input
value={token ?? ""}
onChange={(e) => setToken(e.target.value)}
/>
);
}
// Mount
createRoot(document.getElementById("root")!).render(
<P47hProvider>
<App />
</P47hProvider>
);
Error Handling
Error handling is explicit. Hooks surface loading and error states so the UI can react predictably.
const [secret, setSecret, { isLoading, error }] = useSecret("key");
// isLoading: true while decrypting or during WASM init
// error: contains Error object if operation failed
No silent failures. No magic retries.
When you probably don’t need this
Next: Hooks Reference — full API documentation for all hooks.