npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@partylayer/react

v3.1.2

Published

Canton Network wallet connection kit for React: CIP-0103 integrations, included wallet runtimes, hooks, themes and a ready-made Connect Wallet button.

Readme

@partylayer/react

The ready-made Canton wallet connection kit for React

npm version TypeScript React License: MIT


Overview

@partylayer/react provides React hooks and components for integrating Canton Network wallet connectivity into your React application. Built on top of @partylayer/sdk, it offers a declarative API with built-in state management and CIP-0103 wallet integrations.

Coming from RainbowKit? Read the Canton React wallet guide. PartyLayer is independent from RainbowKit and uses Canton party identity and transaction semantics. Get integration help.

This guide covers 3.1.0+. See release validation for acceptance scope and release status.

Features

  • React Hooks: useSession, useWallets, useConnect, useSignMessage, and more
  • Ready-to-Use Components: a pre-built wallet modal (with wallet search and a "New to Canton wallets?" explainer) and a ConnectButton with a deterministic account avatar and a copy-address dropdown
  • Themeable: callable lightTheme/darkTheme with an accent color, radius, blur, and font stack, ready-made accentPresets, and a dynamic light/dark option
  • State Management: Automatic session state synchronization
  • TanStack Query data layer: a @partylayer/react/query entrypoint for DAML reads/writes (useDamlContract, useChoice), CIP-0104 cost (useTransactionCostEstimate, usePaidTrafficCost), Suspense twins, and optimistic updates
  • TypeScript: Full type safety for all hooks and components
  • SSR Compatible: Works with Next.js and other SSR frameworks (cookieStorage hydration, Server Components compatible)

One installation, shared wallet configuration

npm install @partylayer/react @tanstack/react-query
import { PartyLayerKit, ConnectButton } from '@partylayer/react';

<PartyLayerKit network="devnet" appName="My dApp">
  <ConnectButton />
</PartyLayerKit>

The SDK and reviewed official wallet SDKs are included. Wallets are filtered by network and channel. Use channel="beta" on Devnet for Vala. Enable WalletConnect with walletConnect={{ projectId: 'your-project-id' }} and Bron with bron={oauthAndApiConfig}. Keep configuration objects stable (outside the component or with useMemo). No wallet SDK imports or per-wallet installs are required. adapters replaces defaults; additionalAdapters extends them. Hosted wallets still require the user's own login.

Supported Wallets

This generated stable-catalog table describes effective PartyLayer capabilities. Check the picker and session.capabilitiesSnapshot at runtime; capability metadata is not live acceptance evidence. Vala is an additional Devnet beta entry. Wallet SDKs are included; WalletConnect and Bron require application-owned configuration. Send is Mainnet-only in the catalog.

| Wallet | Networks | Capabilities | Opt-in | Additional setup | |--------|----------|--------------|--------|---------| | Console Wallet | devnet, testnet, mainnet | signMessage, submitTransaction, restore | No | Included | | 5N Loop | devnet, mainnet | signMessage, submitTransaction, ledgerApi, restore, events | No | Included | | Cantor8 | devnet, mainnet | submitTransaction, events | No | Included | | Bron | devnet, testnet, mainnet | signMessage, signTransaction, ledgerApi, restore | Yes | Your OAuth/API configuration | | Nightly | devnet, testnet, mainnet | signMessage, submitTransaction, ledgerApi, restore, events | No | Included | | Cauri Wallet | devnet, mainnet | signMessage, submitTransaction | No | Included | | OneSwap V2 Wallet | devnet, mainnet | signMessage, submitTransaction | No | Included | | Send | mainnet | signMessage, submitTransaction, ledgerApi, restore, events | No | Included | | Walley | mainnet, testnet, devnet | signMessage, submitTransaction | No | Included | | WalletConnect | devnet, testnet, mainnet | signMessage, submitTransaction, ledgerApi, restore, events | Yes | Your project ID |

Try it live: PartyLayer Studio: runnable, editable scenarios · Pattern Cookbook: copy-paste recipes.


Installation

npm install @partylayer/react @tanstack/react-query

@tanstack/react-query is a required peer dependency. The data hooks in the @partylayer/react/query entrypoint are built on TanStack Query, and you supply the QueryClient via QueryClientProvider (the same model wagmi uses). The base session and connect surface (the main entrypoint: useSession, useAccount, useConnect, ConnectButton, WalletModal, PartyLayerKit) works without it; the QueryClientProvider is required only for the /query data hooks.


Quick Start

Use the kit and the default button in an existing React application:

// App.tsx — use a 'use client' boundary in Next.js.
import { PartyLayerKit, ConnectButton } from '@partylayer/react';

export default function App() {
  return (
    <PartyLayerKit network="devnet" appName="My dApp">
      <ConnectButton />
    </PartyLayerKit>
  );
}

PartyLayerKit owns discovery, client cleanup, theme and session context. The button opens wallet selection, handles connection states and displays the account menu. The modal shows Powered by PartyLayer by default. Custom UI and attribution configuration are available when needed; no stylesheet import is required.

Use the complete quick start for Vite and Next.js App Router, including the root layout. Starting a new app?

npm create partylayer-app@latest my-dapp -- --template react-vite --pm npm

Read the account

import { useAccount } from '@partylayer/react';

export function Account() {
  const { isConnected, status, party, networkId } = useAccount();
  if (!isConnected) return <p>Wallet: {status}</p>;
  return <p>{party} · {networkId}</p>;
}

Render this inside the kit. Connection is not application authentication: use the authentication guide for backend-verified sign-in.

Add optional data hooks

For @partylayer/react/query, wrap the kit with QueryClientProvider. In a Next.js client provider, use a per-instance stable QueryClient:

'use client';

import { useState, type ReactNode } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { PartyLayerKit } from '@partylayer/react';

export function Providers({ children }: { children: ReactNode }) {
  const [queryClient] = useState(() => new QueryClient());
  return (
    <QueryClientProvider client={queryClient}>
      <PartyLayerKit network="devnet" appName="My dApp">
        {children}
      </PartyLayerKit>
    </QueryClientProvider>
  );
}

The base connect UI does not require QueryClientProvider. Do not create a new client on each render or share an SSR QueryClient across requests.

Hooks Reference

useSession()

Reactive session state + actions (UseSessionReturn). Re-renders on every session change.

const { status, account, networkId, isConnected, connect, disconnect, on } = useSession();

if (isConnected) {
  console.log('Party ID:', account?.partyId);
  console.log('Network:', networkId);
}

In v2, useSession() returns the reactive session store (UseSessionReturn). The legacy SDK Session getter ({ sessionId, walletId, … }) is preserved as useClientSession() (deprecated). See the v1 to v2 migration guide.

useWallets()

Returns the list of available wallets and loading state.

const { wallets, isLoading, error } = useWallets();

return (
  <ul>
    {wallets.map((wallet) => (
      <li key={wallet.walletId}>
        <img src={wallet.icon} alt={wallet.name} />
        {wallet.name}
      </li>
    ))}
  </ul>
);

useConnect()

Hook for connecting to a wallet.

const { connect, isConnecting, error } = useConnect();

// Connect to first available wallet
await connect();

// Connect to specific wallet
await connect({ walletId: 'console' });

// With options
await connect({
  walletId: 'loop',
  timeoutMs: 60000,
  requiredCapabilities: ['signMessage', 'signTransaction'],
});

useDisconnect()

Hook for disconnecting from the current wallet.

const { disconnect, isDisconnecting } = useDisconnect();

<button onClick={disconnect} disabled={isDisconnecting}>
  Disconnect
</button>

useSignMessage()

Hook for signing messages.

const { signMessage, isSigning, error } = useSignMessage();

const handleSign = async () => {
  const result = await signMessage({ message: 'Hello, Canton!' });
  console.log('Signature:', result.signature);
};

usePartyLayer()

Returns the underlying SDK client for advanced usage.

const client = usePartyLayer();

// Access SDK methods directly
const wallets = await client.listWallets();

useRegistryStatus()

Returns the wallet registry status.

const status = useRegistryStatus();

if (status?.stale) {
  console.log('Registry data may be outdated');
}

Data hooks (@partylayer/react/query)

v2 adds a TanStack Query powered entrypoint, @partylayer/react/query, for reading and writing ledger data and for cost estimation. These hooks require a QueryClientProvider (see Installation). PartyLayer does not own ledger transport: you supply the fetcher, and the hook wraps it in useQuery / useMutation for caching, loading state, and invalidation. (The entrypoint also exports query-backed variants of the wallet hooks: useConnect, useWallets, useDisconnect, useSignMessage, useSubmitTransaction.)

DAML read and write (Model 2)

import { useDamlContract, useChoice } from '@partylayer/react/query';

// read: generic over the contract type; you supply the `read` fetcher.
const { contract, isLoading } = useDamlContract<MyContract>({ read: fetchContract });

// write: generic over result/variables; exposes exerciseChoice / exerciseChoiceAsync.
const { exerciseChoice, exerciseChoiceAsync } = useChoice<MyResult, MyVars>({ exercise });

null is a valid resolved value (the contract is absent), not an error.

CIP-0104 cost

import { useTransactionCostEstimate, usePaidTrafficCost } from '@partylayer/react/query';

const { costEstimate } = useTransactionCostEstimate({ estimate: fetchEstimate });
const { paidTrafficCost } = usePaidTrafficCost({ fetch: fetchPaid });
  • useTransactionCostEstimate: the pre-submission CostEstimation.
  • usePaidTrafficCost: the post-execution paid cost.

Suspense twins

The query hooks have useSuspense* twins (useSuspenseTransactionCostEstimate, useSuspensePaidTrafficCost, useSuspenseWallets) for declarative loading inside a React <Suspense> boundary: the value is always present (no loading flag), and the boundary shows the fallback while it resolves.

Optimistic updates

optimisticMutationOptions wires an optimistic cache update with automatic rollback on error into useChoice (the wagmi-style onMutate/rollback pattern). The partyLayerKeys factory (also exported here) produces the hierarchical cache keys, so manual cache reads/writes line up with the hooks.

import { useChoice, optimisticMutationOptions } from '@partylayer/react/query';

const { exerciseChoice } = useChoice({
  exercise,
  mutation: optimisticMutationOptions({ queryClient, queryKey, update }),
});

See the v1 to v2 migration guide and the Pattern Cookbook for full recipes, optimistic patterns, and the SSR (cookieStorage) and Server Components details.


Components

PartyLayerProvider

The context provider that must wrap your application.

<PartyLayerProvider client={client}>
  {children}
</PartyLayerProvider>

Props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | client | PartyLayerClient | Yes | The SDK client instance | | children | ReactNode | Yes | Child components |

WalletModal

A pre-built modal for wallet selection.

<WalletModal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  // optional: the modal self-closes via onClose and the session is observable
  // via useSession()/useAccount(); pass it only to get the session id directly.
  onConnect={(sessionId) => console.log('Connected:', sessionId)}
/>

Props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | isOpen | boolean | Yes | Whether the modal is visible | | onClose | () => void | Yes | Called when modal should close | | onConnect | (sessionId: string) => void | No | Optional; called with the new session id after a successful connection | | walletIcons | Record<string, string> | No | Override wallet logos by wallet id | | walletOrder | readonly string[] | No | Wallet ids in display order; unlisted wallets fall to the end | | showAttribution | boolean | No | Show the muted "Powered by PartyLayer" footer line (default true) | | disclaimer | ReactNode | No | Optional legal line (e.g. Terms / Privacy) shown above the footer | | showWalletGuide | boolean | No | Show the "New to Canton wallets?" explainer row (default true) |

The modal also shows a search field once the wallet list is long enough, and a clean transport label under each wallet (for example "Browser Extension" or "Scan to connect").

ConnectButton

A drop-in button that opens the wallet modal, then, once connected, shows a deterministic account avatar with the truncated party id and a dropdown with a copy-address action and disconnect.

import { ConnectButton } from '@partylayer/react';

<ConnectButton accountStatus="full" />

Props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | label | string | No | Text when disconnected (default "Connect Wallet") | | accountStatus | 'avatar' \| 'address' \| 'full' | No | What the connected button shows (default 'full' = avatar + id) | | connectedLabel | 'address' \| 'wallet' \| 'custom' | No | Which identity to display when connected | | formatAddress | (partyId: string) => string | No | Custom formatter (with connectedLabel="custom") | | showDisconnect | boolean | No | Show the dropdown with copy and disconnect (default true) | | className / style | string / CSSProperties | No | Styling overrides |

Keyboard behavior: The wallet dialog moves focus inside on open, wraps Tab and Shift+Tab, and restores the opener after closing. The connected account menu supports Enter/Space, Arrow Up/Down, Home/End and Escape; Tab leaves the menu. Avatar-only buttons have an accessible account name. Actions use type="button" so embedding the component in a form does not submit the form. Vendor approval surfaces keep their own keyboard handling.

UI language and direction

PartyLayerKit supports English (default) and Turkish. Set locale="tr" or locale="tr-TR"; unsupported language tags fall back to English. Set direction="rtl" when embedding the wallet UI in a right-to-left layout.

<PartyLayerKit network="devnet" appName="My dApp" locale="tr-TR" direction="ltr">
  <ConnectButton />
</PartyLayerKit>

The setting covers PartyLayer's connection dialog, account menu, accessible labels, CostPreview, TransactionToast and SynchronizerSwitcher. Changing language or direction does not recreate the SDK client or disconnect the wallet. The server and client use the same explicit setting; PartyLayer does not guess the browser language or mutate the application's document language.

Advanced PartyLayerProvider compositions can wrap their UI with PartyLayerLocaleProvider, which accepts the same locale and direction props. Application copy, custom button labels, wallet names, identifiers, provider error details and wallet-owned approval screens remain under their respective owners. Your app controls cost/number formatting through the existing formatting props.

PartyAvatar

A small deterministic avatar generated from a Canton party id (the same id always yields the same avatar). Reused inside ConnectButton, and exported so you can render the same identity mark elsewhere.

import { PartyAvatar } from '@partylayer/react';

<PartyAvatar id={partyId} size={24} />

| Prop | Type | Required | Description | |------|------|----------|-------------| | id | string | Yes | The party id the avatar is generated from | | size | number | No | Diameter in px (default 20) | | className / style | string / CSSProperties | No | Styling overrides |


Theming

lightTheme and darkTheme are callable: call them with a few friendly overrides to customize, or pass them as-is. The default look is unchanged.

import { PartyLayerKit, darkTheme, accentPresets } from '@partylayer/react';

// A custom accent, larger radius, and a stronger backdrop blur:
<PartyLayerKit
  network="mainnet"
  appName="My dApp"
  theme={darkTheme({ accentColor: '#7B3FE4', borderRadius: 'large', overlayBlur: 'large' })}
>
  {children}
</PartyLayerKit>

// Or a ready-made preset:
<PartyLayerKit network="mainnet" appName="My dApp" theme={darkTheme({ ...accentPresets.purple })}>
  {children}
</PartyLayerKit>

ThemeOverrides (accepted by lightTheme(...) / darkTheme(...) / createTheme(base, overrides)):

| Field | Type | Description | |------|------|-------------| | accentColor | string | Sets the primary accent (a hover shade is derived) | | accentColorForeground | string | Text/icon color on the accent (auto-derived if omitted) | | borderRadius | 'none' \| 'small' \| 'medium' \| 'large' \| string | Corner radius keyword or a raw CSS length | | overlayBlur | 'none' \| 'small' \| 'large' \| string | Modal backdrop blur keyword or a raw CSS length | | fontStack | 'system' \| 'rounded' \| string | Font family keyword or a raw CSS font-family | | colors | Partial<PartyLayerTheme['colors']> | Deep color overrides |

accentPresets ships partyYellow, blue, green, purple, orange, pink, and red. Pass a static theme, or a dynamic { lightMode, darkMode } object that follows the OS preference. The showAttribution and disclaimer props are also available on PartyLayerKit and apply to the modal footer.


Next.js Integration

Put PartyLayerKit in a client provider component and render it from your Server Component root layout. The complete Next.js example includes both files. The next-ssr CLI template additionally demonstrates an explicit cookie-based UI session projection.

Cookie state is a display hint, not proof of wallet authorization or server login. Protect server routes with independently verified backend sessions. Native wallet restoration checks the live party/network and may require one reconnect for older caches. See protocol migration.

TypeScript

All hooks and components are fully typed:

import type { Session, WalletInfo, UseSessionReturn } from '@partylayer/react';

// Reactive session: state + actions
const session: UseSessionReturn = useSession();

// Legacy SDK session getter (deprecated alias)
const legacy: Session | null = useClientSession();

// Wallet info type
const { wallets }: { wallets: WalletInfo[] } = useWallets();

Custom UI

The default ConnectButton is the recommended integration. For a custom picker, use WalletModal, useWallets, useConnect, useDisconnect and useAccount inside the same kit. Start popup connection from a user gesture, preserve keyboard focus and inspect session capabilities before exposing an operation.

See the hook reference and WalletModal. Custom UI owns its loading, rejection, timeout, accessibility and account-state presentation.


Related Packages

| Package | Description | |---------|-------------| | @partylayer/sdk | SDK included as a dependency | | @partylayer/core | Core types and abstractions |


Links


License

MIT

Session hooks

useSession / useAccount / useAccountEffect are thin React bindings over the @partylayer/session store, created by PartyLayerProvider / PartyLayerKit. SSR-safe (no window/BroadcastChannel at module or hook scope).

const { status, account, networkId, connect, disconnect, on } = useSession();
const { address, isConnected, chain } = useAccount();
useAccountEffect({
  onConnect: ({ account }) => {/* … */},
  onDisconnect: () => {/* … */},
  onPartyChanged: ({ previous, current }) => {/* invalidate caches */},
});

Adopt the session layer via PartyLayerKit:

<PartyLayerKit … sessionOptions={{
  storage: createEncryptedIndexedDBStorage(), // @partylayer/session
  persistSnapshot: true,
  reconnect: DEFAULT_RETRY_POLICY,
  broadcast: true,                            // multi-tab sync
}}>…</PartyLayerKit>

Migrating from v1

In v2, useSession() is the reactive session-store hook (UseSessionReturn: live SessionState plus connect/disconnect/restore/on). The previous SDK-layer getter ((): Session | null) is preserved verbatim as useClientSession() (deprecated). v2 also moves the data layer to TanStack Query (the @partylayer/react/query entrypoint), which adds the QueryClientProvider setup shown above.

| Before (v1) | After (v2) | |---|---| | const session = useSession(); session?.partyId | const session = useClientSession(); session?.partyId | | (no reactive session) | const { status, account, connect } = useSession() |

For the full upgrade (renames, the query peer, and the provider change), see the v1 to v2 migration guide.

Vue parity

The Vue bindings ship as @partylayer/vue with the shared connection/account composables below. The new authentication and transaction-journal React components/hooks do not imply complete Vue feature parity.

| React (@partylayer/react) | Vue (@partylayer/vue) | |---|---| | useSession() | useSession() | | useAccount() | useAccount() | | useAccountEffect() | useAccountEffect() | | useClientSession() (legacy) | None (not ported) |

The recommended UI is PartyLayer's ConnectButton. Its connection modal includes “Powered by PartyLayer” by default, as do the generated starters. Custom UI remains available for advanced use. For authentication challenges, include nonce and domain in the message being signed; separate nonce/domain metadata is not a cryptographic binding.

For application sign-in, pass a stable authentication backend integration to PartyLayerKit. The same ConnectButton then offers explicit sign-in and app sign-out. useAuthentication() exposes backend session status, pending/error state, canSignIn and refresh. Custom buttons wait for canSignIn and invoke signIn() directly in their click handler to preserve hosted-wallet popup activation. Implement server challenge storage, CSRF/browser binding, exact message signature verification and independent party-key authorization before enabling it. See the authentication guide; a wallet connection or client-side status does not authorize backend requests.

Use useTransactionFlow to submit once and independently reconcile ledger outcomes. Transactions from this hook appear in the default account panel automatically; useRecentTransactions and RecentTransactions support custom activity views. The journal is private in-memory UI activity, scoped by wallet/party/network, not a full ledger indexer. An unknown outcome never triggers automatic submission. All ledger-write mutation hooks ignore automatic retry settings; check ledger state before an explicit new attempt. See Transaction lifecycle.

Pass authorized, party/network-bound holdings to ConnectButton to show balances in the same account panel, or use TokenBalances for a custom view. Exact-decimal summaries separate instrument admin/id and reported locks. Data comes from your authorized backend or a supported wallet ledger proxy; unavailable reads do not become zero balances. See Wallet balances.