JSPM

@solutiofi/connectorkit-svelte

0.2.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 17
  • Score
    100M100P100Q49741F
  • License MIT

Solana wallet connection library for Svelte 5, powered by @solana/connector headless API

Package Exports

  • @solutiofi/connectorkit-svelte

Readme

connectorkit-svelte

The ultimate Solana wallet connection library for Svelte 5. Powered by @solana/connector headless API and built with Svelte Runes.

npm version License: MIT

Features

  • Zero-Config Polyfills - Works with Vite/SvelteKit out of the box (no vite-plugin-node-polyfills needed!)
  • 🎨 Fully Themeable - Customize every color with CSS variables
  • 📱 Mobile-First - Deep links to wallet apps + WalletConnect QR codes
  • 🔧 Svelte 5 Runes - Built from the ground up for the new reactivity model
  • 🌐 Wallet Standard - Supports all modern Solana wallets (Phantom, Solflare, Backpack, etc.)
  • ✍️ Signing - Sign messages and transactions with full TypeScript support
  • 💰 Balances - Auto-fetching for SOL and SPL tokens
  • 🎯 Filtering - precise control over which wallets are shown, hidden, or featured
  • 👥 Multi-Account - seamless switching between multiple accounts in a single wallet

Installation

npm install connectorkit-svelte @solana/connector @solana/web3.js
# or
pnpm add connectorkit-svelte @solana/connector @solana/web3.js

Quick Start

  1. Wrap your application with SvelteConnectorProvider:
<!-- +layout.svelte -->
<script lang="ts">
  import { SvelteConnectorProvider, WalletButton } from 'connectorkit-svelte';

  const config = {
    appName: 'My Solana App',
    network: 'mainnet',
    projectId: 'YOUR_WALLETCONNECT_ID' // Optional
  };
</script>

<SvelteConnectorProvider {config}>
  <nav>
    <WalletButton />
  </nav>
  <slot />
</SvelteConnectorProvider>
  1. Use the context in valid child components:
<!-- +page.svelte -->
<script lang="ts">
  import { getConnectorContext, TokenList } from 'connectorkit-svelte';
  
  const ctx = getConnectorContext();
</script>

{#if ctx.state.isConnected}
  <h1>Welcome, {ctx.state.publicKey}</h1>
  <TokenList />
{/if}

Configuration

Detailed configuration reference for SvelteConnectorConfig:

interface SvelteConnectorConfig {
  // --- Basic ---
  appName: string;              // Name shown in wallet connection prompts
  appUrl?: string;              // URL of your app (for wallet metadata)
  network?: 'mainnet' | 'devnet' | 'testnet' | 'localnet'; // Default: 'mainnet'
  
  // --- Connection ---
  autoConnect?: boolean;        // Attempt to auto-connect on load (default: false)
  rpcUrl?: string;              // Custom RPC URL (defaults to public Alchemy endpoint)
  debug?: boolean;              // Enable verbose logging
  
  // --- UI/UX ---
  walletOrder?: string[];       // Sort wallets by name: ['Phantom', 'Backpack']
  walletLimit?: number;         // Max wallets to show before "More" (default: 4)
  imageProxy?: string;          // Proxy URL for wallet icons to avoid CORS issues
  
  // --- Filtering ---
  wallets?: {
    allowList?: string[];       // Strict list: ONLY show these wallets
    denyList?: string[];        // Blacklist: NEVER show these wallets
    featured?: string[];        // Highlight these wallets at the top with a badge
  };

  // --- Network Switching ---
  clusters?: {                  // Custom networks for ClusterSelector
    name: string;
    id: string;
    rpcUrl: string;
    wsUrl?: string;
  }[];

  // --- WalletConnect (Optional) ---
  walletConnect?: {
    projectId: string;          // Get from https://cloud.walletconnect.com
    metadata?: {
      name: string;
      description: string;
      url: string;
      icons: string[];
    };
  };
}

Component Reference

<WalletButton />

The primary connect button. Automatically handles "Connect", "Disconnect", "Copy Address", and "Change Wallet".

Prop Type Default Description
size 'sm' | 'md' | 'lg' 'md' Scaling of the button
showIcon boolean true Show wallet icon when connected
class string '' Custom classes

<WalletModal />

A standalone modal component. Use this if you want to create your own trigger button.

<script>
  let isOpen = $state(false);
</script>
<button onclick={() => isOpen = true}>Connect Custom</button>
<WalletModal bind:open={isOpen} />
Prop Type Default Description
open boolean false Control modal visibility
title string 'Connect Wallet' Modal title text
onclose () => void - Called when modal closes
footer Snippet - Custom footer content (see below)

You can pass a custom footer to add additional functionality like Ledger or hardware wallet connections:

<WalletModal bind:open={isOpen}>
  {#snippet footer()}
    <button onclick={handleLedgerConnect}>
      🔒 Connect Ledger
    </button>
  {/snippet}
</WalletModal>

<ClusterSelector />

A dropdown to switch between networks (Mainnet/Devnet/Testnet) or custom clusters.

Multi-Account Support

If a connected wallet provides multiple accounts, connectorkit-svelte automatically handles them. The <WalletButton /> and <WalletDropdown /> include a built-in UI for switching accounts.

The selected account is persisted per-wallet, so users don't need to re-select when they reconnect.

<TokenList />

Displays a list of SPL tokens held by the connected wallet.

  • Auto-fetches from RPC
  • Shows token icons, symbols, and formatted balances
  • Filters out zero-balance tokens

<AddressDisplay />

Displays a truncated wallet address with click-to-copy.

Prop Type Default Description
address string required The address to display
chars number 4 Chars to show (e.g. ABCD...WXYZ)
copyable boolean false Enable copy-to-clipboard

Hooks & API

Access the connector state reactively anywhere in your app:

import { getConnectorContext } from 'connectorkit-svelte';

const ctx = getConnectorContext();

State Properties

  • ctx.state.isConnected: boolean
  • ctx.state.publicKey: string | null
  • ctx.state.allAccounts: WalletAccount[] (All available accounts)
  • ctx.state.isConnecting: boolean
  • ctx.state.error: WalletError | null
  • ctx.currentCluster: ClusterConfig used for network switching
  • ctx.currentRpcUrl: string current RPC endpoint

Methods

  • ctx.connect(walletId): Connect to a specific wallet
  • ctx.disconnect(): Disconnect current wallet
  • ctx.signMessage(message): Sign a byte array
  • ctx.signTransaction(tx): Sign a serialized transaction
  • ctx.signAndSendTransaction(tx, options): Sign and submit to network
  • ctx.selectCluster(id): Switch network
  • ctx.selectAccount(address): Switch active account

Theming

All styles are defined as CSS custom properties. Light mode is the default; add .dark class to body for dark mode.

Complete CSS Variable Reference

Variable Light Mode Dark Mode Description
Brand Colors
--sck-primary #008AFF #3DA6FF Main action color
--sck-primary-hover #0075D9 #008AFF Hover state
Backgrounds
--sck-bg #FBFCFD #191C21 Modal/dropdown background
--sck-bg-secondary #F4F5F7 #272C33 Card backgrounds
--sck-bg-hover #E6E7EB #30363F Hover backgrounds
Text
--sck-text #1F2329 #FBFCFD Primary text
--sck-text-muted #5B6778 #939EAE Muted text
Borders
--sck-border #CBD1D8 #383F4A Border color
Status Colors
--sck-success #248C3E #34D058 Success states
--sck-error #E42E2C #F85149 Error states
--sck-warning #FFA500 #FFCC00 Warning states

Enabling Dark Mode

Add the .dark class to the body element to activate dark mode:

<script>
  import { onMount } from 'svelte';
  let isDark = $state(true);

  onMount(() => {
    // Restore from localStorage or use system preference
    const saved = localStorage.getItem('theme');
    isDark = saved ? saved === 'dark' : window.matchMedia('(prefers-color-scheme: dark)').matches;
    applyTheme();
  });

  function toggleTheme() {
    isDark = !isDark;
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
    applyTheme();
  }

  function applyTheme() {
    document.body.classList.toggle('dark', isDark);
  }
</script>

<button onclick={toggleTheme}>
  {isDark ? '☀️' : '🌙'}
</button>

Troubleshooting & FAQ

"Global is not defined" or "Buffer is not defined"?

You generally do not need to configure this manually. connectorkit-svelte automatically polyfills global, Buffer, and process in the browser environment when the provider mounts.

Does this work with SvelteKit SSR?

Yes. The library checks for window before running any wallet logic. However, you should ensure <SvelteConnectorProvider> is only rendered in the client or handles checking browser from $app/environment if you run into hydration mismatches (though we handle most cases internally).

My wallet isn't showing up?

  1. Ensure the wallet is installed and supports the Wallet Standard (most do).
  2. Check if you have wallets.allowList configured and the wallet is missing from it.
  3. Check wallets.denyList.

Mobile wallets aren't detected?

On mobile Safari/Chrome, wallet extensions can't inject—wallets are standalone apps. connectorkit-svelte handles this automatically:

Native Mobile App Support (Automatic):

  • On mobile devices, wallets like Phantom, Solflare, Backpack, Jupiter, and Magic Eden are automatically detected and added to the wallet list.
  • They appear as standard wallets in the connect modal.
  • Tapping them initiates a secure Deep Link connection (redirects to the wallet app).
  • After approval, the wallet redirects back to your dApp, and the connection is automatically established.

WalletConnect (recommended as fallback): Configure WalletConnect for universal mobile support:

const config = {
  appName: 'My App',
  network: 'mainnet',
  walletConnect: {
    projectId: 'YOUR_PROJECT_ID', // Free at https://cloud.walletconnect.com
    metadata: {
      name: 'My App',
      description: 'My Solana dApp',
      url: 'https://myapp.com',
      icons: ['https://myapp.com/icon.png']
    }
  }
};

Mobile connection flow:

  1. User opens your dApp in mobile Safari/Chrome
  2. Taps "Connect Wallet"
  3. Sees Phantom, Solflare, etc. in the standard wallet list
  4. Taps "Phantom" -> Redirects to Phantom app -> User Connects
  5. Redirects back to your dApp -> Wallet is designated as "Connected"

Pro tip: If users open your dApp from within a wallet's browser (e.g., Phantom's built-in browser), wallets inject automatically—no deep links needed.

License

MIT © 2026 Connectorkit Authors