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

v2.1.0

Published

React hooks and components for PartyLayer

Readme

@partylayer/react

React hooks and components for PartyLayer

npm version TypeScript React License: MIT


Overview

@partylayer/react provides React hooks and components for seamlessly 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.

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 (v2): 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)

Supported Wallets

| Wallet | Networks | Capabilities | Opt-in | Adapter | |--------|----------|--------------|--------|---------| | Console Wallet | devnet, testnet, mainnet | signMessage, signTransaction, submitTransaction, transactionStatus | No | @partylayer/adapter-console | | 5N Loop | devnet, testnet, mainnet | signMessage, submitTransaction, transactionStatus | No | @partylayer/adapter-loop | | Cantor8 | devnet, testnet, mainnet | signMessage, signTransaction | No | @partylayer/adapter-cantor8 | | Bron | devnet, testnet, mainnet | signMessage, signTransaction | Yes | @partylayer/adapter-bron | | Nightly | devnet, testnet, mainnet | signMessage, submitTransaction | No | @partylayer/adapter-nightly | | Send | mainnet | signMessage, submitTransaction, transactionStatus | No | @partylayer/adapter-send | | Walley | mainnet, testnet, devnet | signMessage, submitTransaction, transactionStatus | No | @k2flabs/walley-dapp-sdk | | WalletConnect | devnet, testnet, mainnet | signMessage, submitTransaction | Yes | @partylayer/adapter-walletconnect |

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


Installation

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

@tanstack/react-query is a required peer dependency of v2. 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

1. Set Up the Provider

Wrap your app in QueryClientProvider (you own the QueryClient; PartyLayer does not create one) and PartyLayerProvider. PartyLayerKit is the zero-config alternative to PartyLayerProvider; the nesting is the same.

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createPartyLayer } from '@partylayer/sdk';
import { PartyLayerProvider } from '@partylayer/react';

const client = createPartyLayer({
  network: 'devnet',
  app: { name: 'My dApp' },
});

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <PartyLayerProvider client={client}>
        <MyApp />
      </PartyLayerProvider>
    </QueryClientProvider>
  );
}

The base session and connect hooks (useSession, useAccount, useConnect, etc.) work without QueryClientProvider. It is required for the @partylayer/react/query data hooks (DAML reads/writes, cost estimation). Migrating from v1? See the v1 to v2 migration guide.

2. Use Hooks in Your Components

import { useAccount, useConnect, useDisconnect } from '@partylayer/react';

function WalletButton() {
  const { isConnected, party } = useAccount();
  const { connect, isConnecting } = useConnect();
  const { disconnect } = useDisconnect();

  if (isConnected) {
    return (
      <div>
        <p>Connected: {party}</p>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    );
  }

  return (
    <button onClick={() => connect()} disabled={isConnecting}>
      {isConnecting ? 'Connecting...' : 'Connect Wallet'}
    </button>
  );
}

3. Use the Wallet Modal (Optional)

import { useState } from 'react';
import { WalletModal, useAccount } from '@partylayer/react';

function ConnectButton() {
  const [isOpen, setIsOpen] = useState(false);
  const { isConnected, party } = useAccount();

  if (isConnected) {
    return <p>Connected: {party}</p>;
  }

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Connect Wallet</button>
      <WalletModal isOpen={isOpen} onClose={() => setIsOpen(false)} />
    </>
  );
}

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 |

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

For Next.js applications, initialize the client on the client side:

'use client';

import { useEffect, useState } from 'react';
import { createPartyLayer, PartyLayerClient } from '@partylayer/sdk';
import { PartyLayerProvider } from '@partylayer/react';

export function Providers({ children }: { children: React.ReactNode }) {
  const [client, setClient] = useState<PartyLayerClient | null>(null);

  useEffect(() => {
    const cantonClient = createPartyLayer({
      network: 'devnet',
      app: { name: 'My Next.js App' },
    });
    setClient(cantonClient);
    
    return () => cantonClient.destroy();
  }, []);

  if (!client) {
    return <div>Loading...</div>;
  }

  return (
    <PartyLayerProvider client={client}>
      {children}
    </PartyLayerProvider>
  );
}

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();

Complete Example

import { useState } from 'react';
import { createPartyLayer } from '@partylayer/sdk';
import {
  PartyLayerProvider,
  useAccount,
  useWallets,
  useConnect,
  useDisconnect,
  useSignMessage,
  WalletModal,
} from '@partylayer/react';

const client = createPartyLayer({
  network: 'devnet',
  app: { name: 'My dApp' },
});

function WalletStatus() {
  const { isConnected, party, networkId } = useAccount();
  const { wallets, isLoading } = useWallets();
  const { connect, isConnecting } = useConnect();
  const { disconnect } = useDisconnect();
  const { signMessage, isSigning } = useSignMessage();
  const [modalOpen, setModalOpen] = useState(false);

  if (isConnected) {
    return (
      <div>
        <h2>Connected</h2>
        <p>Party: {party}</p>
        <p>Network: {networkId}</p>
        <button
          onClick={() => signMessage({ message: 'Test' })}
          disabled={isSigning}
        >
          {isSigning ? 'Signing...' : 'Sign Message'}
        </button>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    );
  }

  return (
    <div>
      <h2>Not Connected</h2>
      <button onClick={() => setModalOpen(true)}>
        Connect Wallet
      </button>
      <WalletModal
        isOpen={modalOpen}
        onClose={() => setModalOpen(false)}
      />
    </div>
  );
}

export default function App() {
  return (
    <PartyLayerProvider client={client}>
      <WalletStatus />
    </PartyLayerProvider>
  );
}

Related Packages

| Package | Description | |---------|-------------| | @partylayer/sdk | Core SDK (required) | | @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 same surface as composables.

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