Login Customization
This guide covers the connect-modal authentication surface in VeChain Kit. From v2.7 onward the kit owns the entire connection UI for VeWorld and Sync2 — there is no hand-off to dapp-kit's native picker.
What's new in v2.7
Custom in-house connection flow for VeWorld and Sync2. Clicking a wallet button drives
@vechain/dapp-kitprogrammatically (setSource()+connect()) and renders the kit's own "Waiting for signature…" view. WalletConnect's QR modal is preserved because that modal is the QR.Granular
loginMethods:veworld,sync2,wallet-connect,appleare now first-class entries you can pin individually. The legacydappkitvalue still works.Variation A layout: one recommended primary CTA (filled inverted + "recommended" dot) — usually VeWorld in the default config, but the dev controls which method gets the emphasis via
isPrimary; the rest render as outline secondary. "More options ⌄" link footer opens an in-modal sub-view with overflow wallets / socials / ecosystem apps.Themeable accent: spinner, focus rings and the "Waiting for signature…" headline read from
theme.accent.
Overview
VeChain Kit provides four main authentication approaches:
Pre-built
WalletButton— fastest, handles state automatically.Custom button that opens the modal —
useConnectModal().Custom button that triggers a single wallet directly —
useConnectWithDappKitSource(source, setContent).Wallet-only via the legacy dapp-kit modal —
useDAppKitWalletModal().
Method 1: WalletButton
The simplest path. Renders the kit's standard login pill, owns connection state, and switches between login / profile automatically.
'use client';
import { WalletButton } from '@vechain/vechain-kit';
export function Page() {
return <WalletButton />;
}Method 2: Custom button → kit's connect modal
Method 3: Trigger one wallet, no grid
Skip the grid entirely and open the kit's "Waiting for signature…" view straight away — useful when your app is wallet-specific.
Allowed sources: 'veworld' | 'sync2' | 'wallet-connect'. WalletConnect will additionally pop its own QR modal.
Method 4: OAuth from a custom UI (Privy)
For self-hosted Privy apps, you can drive OAuth flows directly:
Configuring the grid: loginMethods
loginMethodsThe order and shape of the connect-modal grid is controlled by loginMethods on <VeChainKitProvider>. Each entry has a method, an optional gridColumn (1–4 — buttons span that many of the 4 columns), and an optional isPrimary flag that controls which button gets the recommended-CTA treatment.
Recommended primary CTA — isPrimary
isPrimaryOne method per grid renders as the recommended CTA: filled inverted surface (dark on light mode, white on dark mode) with a small green dot. The rest render as outline secondary. Two ways the kit picks which:
Explicit — any entry with
isPrimary: true(excludingmore, which is a footer link). If multiple entries setisPrimary, the first one wins.Implicit fallback — when no entry sets
isPrimary, the kit highlights the first visible method in the array. So a minimal config like[{ method: 'google' }, { method: 'apple' }]still gets Google as the recommended CTA without thinking about emphasis.
Currently supported as primary: veworld, google, apple, github. Other methods can sit on the main grid but won't switch to the filled treatment when first / isPrimary: true — they keep their outline look. (Adding more is a one-prop change per button; open an issue if you need it.)
Method values
veworld
dappKit.allowedWallets includes 'veworld'
Custom VeWorld flow + the kit's "Waiting for signature…" view
sync2
dappKit.allowedWallets includes 'sync2'
Custom Sync2 flow + same waiting view
wallet-connect
dappKit.allowedWallets includes 'wallet-connect' + walletConnectOptions.projectId
Triggers WalletConnect's QR modal programmatically (kit's loading view sits behind)
google
privy
Privy Google OAuth (full color "G")
apple
privy
Privy Apple OAuth
github
privy
Privy GitHub OAuth
email
privy
Inline email pill + 6-digit code modal
passkey
privy
Privy WebAuthn
vechain
privy
VeChain cross-app login (single wallet across Privy ecosystem apps)
ecosystem
—
Footer button that opens a sub-view listing x2earn ecosystem apps
more
—
"More options ⌄" link footer → in-modal sub-view with all overflow options
dappkit
dappKit
Legacy. Opens dapp-kit's native picker modal — preserved for backwards compatibility
The 'more' sub-view
'more' sub-viewWhen the user taps More options ⌄, the modal cross-fades into a sub-view that surfaces everything you configured but didn't put on the main grid:
Other wallets — entries in
dappKit.allowedWalletsnot on the main grid (VeWorld / Sync2 / WalletConnect).Other sign-in — natively-rendered Privy methods in
privy.loginMethods(Google, Apple, GitHub, email, passkey). Anything else you configured in Privy (Twitter, Discord, Farcaster, TikTok, LinkedIn, …) is reachable via a fallback link that opens Privy's own modal.Ecosystem apps — the x2earn apps configured via Privy ecosystem.
Items already shown on the main grid are excluded. Sections collapse when they'd be empty. The dev can hide the whole sub-view by omitting 'more' from loginMethods.
Default loginMethods
loginMethodsIf you don't pass loginMethods, the kit picks a sensible default:
Special: only dappkit
dappkitWhen loginMethods is exactly [{ method: 'dappkit', ... }], useConnectModal().open() opens dapp-kit's native picker directly — the kit's modal is never rendered. This preserves the v2.6.x behavior for apps that explicitly pinned dappkit.
Theming the connect modal
The modal honors the theme tokens passed to <VeChainKitProvider>:
Modal surface / overlay / borders —
theme.modal.backgroundColor,theme.modal.border,theme.modal.rounded,theme.overlay.backgroundColor.Text colors —
theme.textColorcascades to primary / secondary / tertiary.Primary button (VeWorld CTA) —
theme.buttons.primaryButton.{bg, color, border, rounded, hoverBg}.Brand accent —
theme.accentcontrols the spinner top arc, focus rings, the "Waiting for signature…" headline and the email-submit link when the address is valid. Default#3b82f6(light) /#60a5fa(dark).
Brand-locked surfaces (intentionally not themed): Google's white tile + colored "G", Apple's glyph, WalletConnect's #3B99FC, GitHub's #24292e, the recommended-provider green dot on VeWorld. These have to remain recognisable as brand icons.
VeWorld mobile in-app browser
When your dApp is opened from inside the VeWorld mobile wallet browser, the kit detects window.vechain.isInAppBrowser and skips the grid entirely — setSource('veworld') + connectV2(null) runs as soon as the connect intent is triggered. The user sees no modal because they're already inside the wallet.
Migrating from v2.6.x
No breaking change for apps that pinned
{ method: 'dappkit' }— it still opens dapp-kit's modal exactly as before.The default
loginMethodschanged. If you did not passloginMethods, the modal previously rendered[vechain, ecosystem, dappkit]and now renders[veworld, google, apple, more](Privy) or[veworld, sync2, wallet-connect](no Privy). To keep the v2.6 grid, pass it explicitly.The granular methods (
veworld,sync2,wallet-connect) are gated ondappKit.allowedWallets. If a method is in yourloginMethodsbut its source isn't inallowedWallets, the button is hidden.
Error handling
The kit handles rejections ('rejected' | 'cancelled' | 'user denied' | 'closed') by returning to the main grid silently. Any other error transitions the modal to the redesigned error view (red disc + Back / Try again). If you drive useConnectWithDappKitSource yourself, the same state machine applies — your setCurrentContent setter is what flips between loading / error / main.
Last updated
Was this helpful?