Packages

@ckb-ccc/connector-react

React connector with Provider component and hooks for CKB wallet integration.

Edit on GitHub

@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

@ckb-ccc/connector-react npm version@ckb-ccc/connector-react npm downloads per week
npm install @ckb-ccc/connector-react
yarn add @ckb-ccc/connector-react
pnpm add @ckb-ccc/connector-react

Quick start

Place Provider at the root of your application (above any component that needs wallet access).

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

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

Call useCcc() inside any descendant component to open the wallet picker and read the connected wallet state.

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

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

  return (
    <div>
      <button onClick={open}>
        {wallet ? `Connected: ${wallet.name}` : "Connect Wallet"}
      </button>
      {signerInfo && <Address />}
    </div>
  );
}

function Address() {
  const { signerInfo } = ccc.useCcc();
  const [address, setAddress] = React.useState("");

  React.useEffect(() => {
    signerInfo?.signer.getRecommendedAddress().then(setAddress);
  }, [signerInfo]);

  return <p>{address}</p>;
}

Provider props

<ccc.Provider
  hideMark={false}
  name="My App"
  icon="https://example.com/icon.png"
  signerFilter={async (signerInfo, wallet) => true}
  defaultClient={new ccc.ClientPublicTestnet()}
  clientOptions={[
    { name: "Testnet", client: new ccc.ClientPublicTestnet() },
    { name: "Mainnet", client: new ccc.ClientPublicMainnet() },
  ]}
  preferredNetworks={[{ addressPrefix: "ckb", signerType: ccc.SignerType.BTC, network: "btc" }]}
>
  {children}
</ccc.Provider>
PropTypeDescription
childrenReactNodeYour application tree
connectorPropsHTMLAttributes<{}>?Additional props to pass to the connector element
hideMarkboolean?Hide the "Powered by CCC" mark in the connector UI
namestring?App name shown in the wallet picker
iconstring?App icon URL shown in the wallet picker
signerFilter(signerInfo, wallet) => Promise<boolean>Filter which wallet/signer combinations appear
signersControllerccc.SignersController?Custom signers controller (advanced)
defaultClientccc.Client?The initial network client
clientOptions{ icon?, client, name }[]?Network options to display in the connector
preferredNetworksccc.NetworkPreference[]?Networks to prefer when a wallet supports multiple

useCcc() hook

const {
  isOpen,      // boolean — whether the wallet picker modal is open
  open,        // () => void — open the wallet picker
  close,       // () => void — close the wallet picker
  disconnect,  // () => void — disconnect the current wallet
  setClient,   // (client: ccc.Client) => void — switch network
  client,      // ccc.Client — current network client
  wallet,      // ccc.Wallet | undefined — connected wallet
  signerInfo,  // ccc.SignerInfo | undefined — connected signer
} = ccc.useCcc();

The hook throws if called outside a <ccc.Provider> tree.

Full example

"use client"; // Required for Next.js App Router

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

function Layout({ children }: { children: React.ReactNode }) {
  return (
    <ccc.Provider
      name="My CKB App"
      defaultClient={new ccc.ClientPublicTestnet()}
    >
      <Header />
      {children}
    </ccc.Provider>
  );
}

function Header() {
  const { open, disconnect, wallet, signerInfo, client } = ccc.useCcc();
  const [address, setAddress] = useState("");

  useEffect(() => {
    if (!signerInfo) {
      setAddress("");
      return;
    }
    signerInfo.signer.getRecommendedAddress().then(setAddress);
  }, [signerInfo]);

  return (
    <header>
      {wallet ? (
        <>
          <span>{address}</span>
          <button onClick={disconnect}>Disconnect</button>
        </>
      ) : (
        <button onClick={open}>Connect</button>
      )}
    </header>
  );
}

Filtering wallets

Use signerFilter to show only specific wallet types:

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

// Show only CKB-native wallets
<ccc.Provider
  signerFilter={async (signerInfo, wallet) => {
    return signerInfo.signer.type === ccc.SignerType.CKB;
  }}
>
  {children}
</ccc.Provider>

Next.js (App Router)

CCC's connector uses React context and browser APIs, so it only works on the client side. Add "use client" to any file that imports from @ckb-ccc/connector-react or renders <ccc.Provider>.

"use client";

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

Forgetting "use client" in Next.js App Router will cause a runtime error: TypeError: (0, react....createContext) is not a function.

On this page