npm package: @solutiofi/connectorkit-svelte
Description: Solana wallet connection library for Svelte 5, powered by @solana/connector headless API
Latest version: 0.2.1

# connectorkit-svelte

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

[![npm version](https://badge.fury.io/js/connectorkit-svelte.svg)](https://badge.fury.io/js/connectorkit-svelte)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/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

```bash
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`:

```svelte
<!-- +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>
```

2. Use the context in valid child components:

```svelte
<!-- +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`:

```typescript
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.

```svelte
<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) |

#### Custom Footer Slot

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

```svelte
<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:

```typescript
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:

```svelte
<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:

```typescript
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