Skip to main content
@ckb-ccc/connector-react is the recommended integration layer for React and Next.js applications. It provides a context Provider, a useCcc hook that exposes the full connector state, and a useSigner hook that returns the active signer whenever a wallet is connected.

Installation

npm install @ckb-ccc/connector-react
import { ccc } from "@ckb-ccc/connector-react";

Provider

Wrap your application (or the subtree that needs wallet access) with ccc.Provider. It renders the wallet selection modal and makes the connector context available to all descendant components.
import { ccc } from "@ckb-ccc/connector-react";

export function App() {
  return (
    <ccc.Provider>
      <YourApp />
    </ccc.Provider>
  );
}

Props

All props are optional except children.
PropTypeDescription
childrenReactNodeThe component subtree that can access the connector context.
namestringDisplay name shown in the connector UI for your application.
iconstringURL of your application icon shown in the connector UI.
defaultClientccc.ClientOverride the default CKB client. Defaults to ClientPublicTestnet.
clientOptions{ icon?: string; client: ccc.Client; name: string }[]List of named network clients users can switch between.
preferredNetworksccc.NetworkPreference[]Networks to prioritise when multiple signers are available.
signerFilter(signerInfo: ccc.SignerInfo, wallet: ccc.Wallet) => Promise<boolean>Async predicate to hide specific signers from the UI.
signersControllerccc.SignersControllerProvide a custom signers controller, bypassing the built-in filter logic.
hideMarkbooleanHide the CCC watermark in the connector modal.
connectorPropsHTMLAttributes<{}>Additional HTML attributes forwarded to the connector web component element.

useCcc

useCcc() returns the full connector context. Call it inside any component that is a descendant of ccc.Provider.
import { ccc } from "@ckb-ccc/connector-react";

function ConnectButton() {
  const { open, disconnect, wallet, signerInfo, client } = ccc.useCcc();

  if (signerInfo) {
    return (
      <div>
        <p>Connected: {wallet?.name}</p>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    );
  }

  return <button onClick={open}>Connect wallet</button>;
}

Return value

PropertyTypeDescription
isOpenbooleanWhether the connector modal is currently visible.
open() => voidOpen the wallet selection modal.
close() => voidClose the wallet selection modal.
disconnect() => voidDisconnect the currently connected wallet.
setClient(client: ccc.Client) => voidSwitch to a different CKB client at runtime.
clientccc.ClientThe active CKB client instance.
walletccc.Wallet | undefinedThe connected wallet metadata, or undefined when no wallet is connected.
signerInfoccc.SignerInfo | undefinedThe active signer info (contains .signer), or undefined when disconnected.
Calling useCcc() outside of a ccc.Provider subtree throws an error. Make sure every component that uses this hook is wrapped by the provider.

useSigner

useSigner() is a convenience hook that returns the active ccc.Signer directly. It returns undefined while no wallet is connected.
import { ccc } from "@ckb-ccc/connector-react";

function SendButton() {
  const signer = ccc.useSigner();

  async function sendCkb() {
    if (!signer) return;

    const { script: toLock } = await ccc.Address.fromString(
      "ckb1...",
      signer.client,
    );
    const tx = ccc.Transaction.from({
      outputs: [{ lock: toLock, capacity: ccc.fixedPointFrom("100") }],
    });
    await tx.completeInputsByCapacity(signer);
    await tx.completeFeeBy(signer);
    const txHash = await signer.sendTransaction(tx);
    console.log("Sent:", txHash);
  }

  return (
    <button onClick={sendCkb} disabled={!signer}>
      Send 100 CKB
    </button>
  );
}

Full example

The following example shows a minimal React app that connects a wallet and sends CKB.
"use client"; // Required for Next.js App Router

import { ccc } from "@ckb-ccc/connector-react";

function WalletControls() {
  const { open, disconnect, wallet, signerInfo } = ccc.useCcc();
  const signer = ccc.useSigner();

  async function handleSend() {
    if (!signer) return;
    const { script: toLock } = await ccc.Address.fromString(
      "ckb1qzda0cr08m85hc8jlnfp3gp88t7re8he4qkd3he97k2tfe4ckb...",
      signer.client,
    );
    const tx = ccc.Transaction.from({
      outputs: [{ lock: toLock, capacity: ccc.fixedPointFrom("100") }],
    });
    await tx.completeInputsByCapacity(signer);
    await tx.completeFeeBy(signer);
    const txHash = await signer.sendTransaction(tx);
    alert(`Sent! TX: ${txHash}`);
  }

  return (
    <div>
      {signerInfo ? (
        <>
          <p>Connected via {wallet?.name}</p>
          <button onClick={handleSend}>Send 100 CKB</button>
          <button onClick={disconnect}>Disconnect</button>
        </>
      ) : (
        <button onClick={open}>Connect wallet</button>
      )}
    </div>
  );
}

export default function App() {
  return (
    <ccc.Provider>
      <WalletControls />
    </ccc.Provider>
  );
}
In Next.js App Router, add "use client" to any file that imports from @ckb-ccc/connector-react. The Provider and hooks use React context and browser APIs that are not available in server components.