Skip to content

React Recipes

These examples assume you’ve already wrapped your app in TatchiPasskeyProvider as shown in the installation guide.

The SDK provides pre-built React components which hooks up a lot of the functionality exposed by the TatchiPasskeyManager.

tsx
import { TatchiPasskeyProvider } from '@tatchi-xyz/sdk/react/provider'

const config = {
  iframeWallet: { walletOrigin: 'https://wallet.tatchi.xyz' },
  relayer: {
    url: 'https://relay.tatchi.xyz',
    accountId: 'w3a-relayer.testnet',
  },
}

function Root() {
  return (
    <TatchiPasskeyProvider config={config}>
      <App />
    </TatchiPasskeyProvider>
  )
}

PasskeyAuthMenu – register / login / recover

PasskeyAuthMenu is a ready‑made registration/login/recovery menu that wires into the passkey flows exposed by useTatchi.

tsx
import {
  useTatchi,
  AuthMenuMode,
  type RegistrationSSEEvent,
  type DeviceLinkingSSEEvent,
} from '@tatchi-xyz/sdk/react'
import { PasskeyAuthMenu } from '@tatchi-xyz/sdk/react/passkey-auth-menu'

export function PasskeySection() {
  const {
    accountInputState,
    registerPasskey,
    loginPasskey,
    tatchi,
  } = useTatchi()

  const targetAccountId = accountInputState.targetAccountId
  const accountExists = accountInputState.accountExists

  const onRegister = () =>
    registerPasskey(targetAccountId, {
      onEvent: (event: RegistrationSSEEvent) => {
        console.log('registration event', event)
      },
    })

  const onLogin = () =>
    loginPasskey(targetAccountId, {
      onEvent: (event) => {
        console.log('login event', event)
      },
    })

  const onRecoverAccount = () =>
    tatchi.recoverAccountFlow({
      accountId: targetAccountId,
      options: {
        onEvent: (event) => console.log('recovery event', event),
        onError: (error) => console.error('recovery error', error),
      },
    })

  const onLinkDeviceEvent = (event: DeviceLinkingSSEEvent) => {
    console.log('link-device event', event)
  }

  return (
    <PasskeyAuthMenu
      defaultMode={accountExists ? AuthMenuMode.Login : AuthMenuMode.Register}
      onLogin={onLogin}
      onRegister={onRegister}
      onRecoverAccount={onRecoverAccount}
      linkDeviceOptions={{
        onEvent: onLinkDeviceEvent,
        onError: (error) => console.error('link-device error', error),
      }}
    />
  )
}

ProfileSettingsButton – account menu + device linking

ProfileSettingsButton shows the current account, lets users export keys, link devices, toggle theme, and adjust confirmation settings.

tsx
import {
  useTatchi,
  DeviceLinkingPhase,
  DeviceLinkingStatus,
} from '@tatchi-xyz/sdk/react'
import { ProfileSettingsButton } from '@tatchi-xyz/sdk/react/profile'

export function HeaderProfile() {
  const { loginState } = useTatchi()

  if (!loginState.isLoggedIn || !loginState.nearAccountId) {
    return null
  }

  return (
    <header className="app-header">
      <ProfileSettingsButton
        nearAccountId={loginState.nearAccountId}
        hideUsername={false}
        onLogout={() => {
          console.log('User logged out')
        }}
        deviceLinkingScannerParams={{
          fundingAmount: '0.05',
          onDeviceLinked: (result) => {
            console.log('Device linked:', result)
          },
          onEvent: (event) => {
            if (event.phase === DeviceLinkingPhase.STEP_7_LINKING_COMPLETE &&
                event.status === DeviceLinkingStatus.SUCCESS) {
              console.log('Device linking complete')
            }
          },
          onError: (error) => {
            console.error('Device linking error:', error)
          },
        }}
      />
    </header>
  )
}

SendTxButtonWithTooltip – embedded transaction button

SendTxButtonWithTooltip embeds the wallet iframe in a button with a rich tooltip that explains what’s being signed.

tsx
import {
  useTatchi,
  ActionType,
  TxExecutionStatus,
} from '@tatchi-xyz/sdk/react'
import { SendTxButtonWithTooltip } from '@tatchi-xyz/sdk/react/embedded'

export function SendGreetingButton() {
  const { tatchi, loginState } = useTatchi()

  if (!loginState.isLoggedIn || !loginState.nearAccountId) {
    return null
  }

  const nearAccountId = loginState.nearAccountId
  const contractId = tatchi.configs.contractId

  return (
    <SendTxButtonWithTooltip
      nearAccountId={nearAccountId}
      txSigningRequests={[
        {
          receiverId: contractId,
          actions: [
            {
              type: ActionType.FunctionCall,
              methodName: 'set_greeting',
              args: { greeting: 'Hello from Tatchi!' },
              gas: '30000000000000',
              deposit: '0',
            },
          ],
        },
      ]}
      options={{
        waitUntil: TxExecutionStatus.EXECUTED_OPTIMISTIC,
        afterCall: (success, result) => {
          if (success) {
            console.log('Tx result', result)
          } else {
            console.warn('Tx failed', result)
          }
        },
        onError: (error) => {
          console.error('Tx error', error)
        },
      }}
      buttonStyle={{
        color: 'white',
        background: 'var(--w3a-colors-primary)',
        borderRadius: '2rem',
        border: 'none',
        height: 44,
        paddingInline: 24,
      }}
      buttonHoverStyle={{
        background: 'var(--w3a-colors-primaryHover)',
      }}
    />
  )
}

From here you can refine styling and hook onEvent into your own toast/notification system, ful a full list of events see progress events. The setup above is enough to get end‑to‑end passkey registration, login, and transaction signing with React components.